├── .gitignore ├── README.md ├── __pycache__ ├── database.cpython-38.pyc ├── main.cpython-38.pyc ├── model.cpython-38.pyc └── schema.cpython-38.pyc ├── database.py ├── main.py ├── model.py ├── requirement.txt ├── schema.py ├── static ├── css │ ├── overview.css │ └── style.css └── js │ └── script.js └── templates ├── index.html └── overview.html /.gitignore: -------------------------------------------------------------------------------- 1 | env -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Server-side Rendering Application with FastAPI 2 | 3 | This repository is a FastAPI application implementing server-side rendering. 4 | 5 | ## Folder Structure: 6 | 7 | - `static`: This folder contains static files such as images, CSS stylesheets, and JavaScript files that are served by the application. These files are typically used to enhance the user interface of the web application. 8 | 9 | - `templates`: This folder contains HTML templates that are used to render dynamic content in the web application. The templates typically use a templating engine like Jinja2 to include dynamic data in the HTML pages. 10 | 11 | - `.gitignore`: This file specifies files and directories that should be excluded from version control when using Git. Typically, this includes files and directories that are specific to the development environment or contain sensitive information that should not be shared. 12 | 13 | - `database.py`: This file contains code that interacts with a database. It typically defines functions or classes that handle database queries and updates. 14 | 15 | - `main.py`: This file contains the main FastAPI application code. It defines the FastAPI instance and the endpoints of the application that handle HTTP requests and responses. 16 | 17 | - `model.py`: This file contains code that defines the data model of the application. It typically defines classes that represent the data entities and their relationships. 18 | 19 | - `requirements.txt`: This file lists the Python packages required by the application. It is used by package managers like pip to install the required packages. 20 | 21 | - `schema.py`: This file contains code that defines the schema of the data entities used in the application. It typically defines classes that represent the schema of the data entities and their relationships. 22 | 23 | 24 | ## Run the Application: 25 | 26 | Clone the repository: 27 | 28 | git clone https://github.com/icode247/Serverside-rendering-FastAPI/ 29 | 30 | Install the required dependencies: 31 | 32 | pip install -r requirements.txt 33 | 34 | Start the FastAPI application: 35 | 36 | uvicorn main:app --reload 37 | 38 | `main` is the name of the Python file containing the FastAPI application. 39 | `app` is the name of the FastAPI instance created in the Python file. 40 | `--reload` flag enables auto-reloading of the server when changes are made to the code. 41 | 42 | Open your web browser and navigate to http://localhost:8000/ to access the root endpoint of your FastAPI application. 43 | 44 | Note: To access other endpoints in the FastAPI application, you can access them by appending the corresponding URL paths to http://localhost:8000/. 45 | 46 | ## Roadmap / TODO: 47 | 48 | - Add more tests to ensure that the application functions correctly and handle errors and edge cases gracefully. 49 | - Consider adding more security measures, such as authentication and authorization, to protect user data and prevent unauthorized access to the application. 50 | - Improve the performance of the application by optimizing database queries and reducing response times. 51 | - Consider deploying the application to a cloud service like AWS or Google Cloud to make it more accessible and scalable. 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /__pycache__/database.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icode247/Serverside-rendering-FastAPI/c8ed38fca0637e2de86b00f93a1b3c07d04a9c5f/__pycache__/database.cpython-38.pyc -------------------------------------------------------------------------------- /__pycache__/main.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icode247/Serverside-rendering-FastAPI/c8ed38fca0637e2de86b00f93a1b3c07d04a9c5f/__pycache__/main.cpython-38.pyc -------------------------------------------------------------------------------- /__pycache__/model.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icode247/Serverside-rendering-FastAPI/c8ed38fca0637e2de86b00f93a1b3c07d04a9c5f/__pycache__/model.cpython-38.pyc -------------------------------------------------------------------------------- /__pycache__/schema.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icode247/Serverside-rendering-FastAPI/c8ed38fca0637e2de86b00f93a1b3c07d04a9c5f/__pycache__/schema.cpython-38.pyc -------------------------------------------------------------------------------- /database.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | SQLALCHEMY_DATABASE_URL = "mysql+mysqlconnector://root@localhost:3306/serversiderendering" 6 | 7 | engine = create_engine( 8 | SQLALCHEMY_DATABASE_URL, 9 | ) 10 | SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) 11 | 12 | Base = declarative_base() -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends, FastAPI, Request, Form 2 | from fastapi.responses import HTMLResponse, JSONResponse 3 | from starlette.responses import RedirectResponse 4 | from sqlalchemy.orm import Session 5 | from fastapi.staticfiles import StaticFiles 6 | from fastapi.templating import Jinja2Templates 7 | from fastapi import Form 8 | from fastapi.encoders import jsonable_encoder 9 | 10 | from model import Movie 11 | import schema 12 | from database import SessionLocal, engine 13 | import model 14 | 15 | app = FastAPI() 16 | 17 | model.Base.metadata.create_all(bind=engine) 18 | 19 | app.mount("/static", StaticFiles(directory="static"), name="static") 20 | templates = Jinja2Templates(directory="templates") 21 | 22 | 23 | def get_database_session(): 24 | try: 25 | db = SessionLocal() 26 | yield db 27 | finally: 28 | db.close() 29 | 30 | 31 | @app.get("/", response_class=HTMLResponse) 32 | async def read_item(request: Request, db: Session = Depends(get_database_session)): 33 | records = db.query(Movie).all() 34 | return templates.TemplateResponse("index.html", {"request": request, "data": records}) 35 | 36 | 37 | @app.get("/movie/{name}", response_class=HTMLResponse) 38 | def read_item(request: Request, name: schema.Movie.name, db: Session = Depends(get_database_session)): 39 | item = db.query(Movie).filter(Movie.id == name).first() 40 | return templates.TemplateResponse("overview.html", {"request": request, "movie": item}) 41 | 42 | 43 | @app.post("/movie/") 44 | async def create_movie(db: Session = Depends(get_database_session), name: schema.Movie.name = Form(...), url: schema.Movie.url = Form(...), rate: schema.Movie.rating = Form(...), type: schema.Movie.type = Form(...), desc: schema.Movie.desc = Form(...)): 45 | movie = Movie(name=name, url=url, rating=rate, type=type, desc=desc) 46 | db.add(movie) 47 | db.commit() 48 | db.refresh(movie) 49 | response = RedirectResponse('/movie', status_code=303) 50 | return response 51 | 52 | 53 | @app.patch("/movie/{id}") 54 | async def update_movie(request: Request, id: int, db: Session = Depends(get_database_session)): 55 | requestBody = await request.json() 56 | movie = db.query(Movie).get(id) 57 | movie.name = requestBody['name'] 58 | movie.desc = requestBody['desc'] 59 | db.commit() 60 | db.refresh(movie) 61 | newMovie = jsonable_encoder(movie) 62 | return JSONResponse(status_code=200, content={ 63 | "status_code": 200, 64 | "message": "success", 65 | "movie": newMovie 66 | }) 67 | 68 | 69 | @app.delete("/movie/{id}") 70 | async def delete_movie(request: Request, id: int, db: Session = Depends(get_database_session)): 71 | movie = db.query(Movie).get(id) 72 | db.delete(movie) 73 | db.commit() 74 | return JSONResponse(status_code=200, content={ 75 | "status_code": 200, 76 | "message": "success", 77 | "movie": None 78 | }) 79 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | from typing import Text 2 | from sqlalchemy.schema import Column 3 | from sqlalchemy.types import String, Integer, Text 4 | from database import Base 5 | 6 | class Movie(Base): 7 | __tablename__ = "Movie" 8 | 9 | id = Column(Integer, primary_key=True, index=True) 10 | name = Column(String(50), unique=True) 11 | desc = Column(Text()) 12 | type = Column(String(20)) 13 | url = Column(String(100)) 14 | rating = Column(Integer) -------------------------------------------------------------------------------- /requirement.txt: -------------------------------------------------------------------------------- 1 | aiofiles==0.7.0 2 | asgiref==3.4.1 3 | autopep8==1.5.7 4 | click==8.0.1 5 | fastapi==0.68.1 6 | FastAPI-SQLAlchemy==0.2.1 7 | greenlet==1.1.2 8 | h11==0.12.0 9 | Jinja2==3.0.1 10 | MarkupSafe==2.0.1 11 | mysql-connector-python==8.0.26 12 | protobuf==3.18.0 13 | pycodestyle==2.7.0 14 | pydantic==1.8.2 15 | PyMySQL==1.0.2 16 | python-multipart==0.0.5 17 | six==1.16.0 18 | SQLAlchemy==1.4.25 19 | starlette==0.14.2 20 | toml==0.10.2 21 | typing-extensions==3.10.0.2 22 | uvicorn==0.15.0 23 | -------------------------------------------------------------------------------- /schema.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | from pydantic import BaseModel 3 | 4 | class Movie(BaseModel): 5 | id = int 6 | name = str 7 | desc = str 8 | type = str 9 | url = str 10 | rating = str 11 | data = date 12 | 13 | class Config: 14 | orm_mode = True -------------------------------------------------------------------------------- /static/css/overview.css: -------------------------------------------------------------------------------- 1 | img{ 2 | width: 100%; 3 | border-radius: 10px; 4 | } 5 | h4{ 6 | text-align: center; 7 | } -------------------------------------------------------------------------------- /static/css/style.css: -------------------------------------------------------------------------------- 1 | body{ 2 | background-color:rgb(236, 234, 232); 3 | } 4 | img { 5 | width: 100%; 6 | border-radius: 10px; 7 | } 8 | .image{ 9 | width: 30%; 10 | } 11 | .details{ 12 | width: 70%; 13 | margin: 12px 14 | } 15 | .card { 16 | border-radius: 20px; 17 | } -------------------------------------------------------------------------------- /static/js/script.js: -------------------------------------------------------------------------------- 1 | form = document.getElementById("updateForm"); 2 | 3 | function updateMovie(id, name, desc) { 4 | fetch("/movie/" + id, { 5 | method: "PATCH", 6 | body: JSON.stringify({ 7 | name, 8 | desc, 9 | }), 10 | }).then((response) => response.json()); 11 | window.location.reload(); 12 | } 13 | 14 | form.addEventListener("submit", (e) => { 15 | e.preventDefault(); 16 | const name = document.getElementById("name").value; 17 | const des = document.getElementById("desc").value; 18 | const id = document.getElementById("id").value; 19 | 20 | updateMovie(id, name, des); 21 | }); 22 | 23 | async function deleteMovie(id) { 24 | const res = await fetch("/movie/" + id, { 25 | method: "DELETE", 26 | }).then((response) => response.json()); 27 | window.location.reload(); 28 | } 29 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 |
15 |
16 |
17 |

Movies

18 | 21 |
22 | {% for movie in data %} 23 |
24 |
25 |
26 |
27 | 28 |
29 |
30 |

{{movie.name}}

31 | 38 |
39 |
40 |
41 |
42 | {% endfor %} 43 | 44 |
45 | 46 | 47 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /templates/overview.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 |
16 | 17 |
18 | 19 |
20 |
21 | 24 |

{{movie.name}}

25 |
26 |
27 | 28 |
29 |

{{movie.desc}}

30 |
31 |
32 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | --------------------------------------------------------------------------------