Building a Movie Database with FastAPI: A Step-by-Step Guide
Why FastAPI?
FastAPI is a modern, high-performance web framework for building APIs. With its server-side rendering features and type hints for Python ≥ v3.6.0, it’s an ideal choice for building robust and efficient applications. Plus, it supports both client-side and server-side development.
Key Features of FastAPI
- Comparable speed to Node.js and Go
- Reduced possibility of human-caused errors
- Excellent support for code editors
- Eliminates code duplication
- Standards-based
Getting Started with FastAPI
To build a movie database application with FastAPI, we’ll need to set up our project structure. Create a new directory called server-side-rendering-with-fastapi and navigate to it. Then, create the following subdirectories:
- static for static files
- templates for HTML pages
- database.py for database connections
- model.py for database models
- schema.py for database schema
Setting Up the Virtual Environment
Create a virtual environment using virtualenv to isolate our Python project. Run the following commands:
python -m virtualenv venv
source venv/bin/activate
Installing Dependencies
Install the necessary packages for our project:
pip install fastapi uvicorn jinja2 python-multipart sqlalchemy mysql-connector-python
Creating the FastAPI Server
Create a main.py file in the project’s root directory and add the following code:
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi.requests import Request
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Welcome to this fantastic app!"}
Setting Up SQLAlchemy
Install SQLAlchemy and MySQL Connector/Python:
pip install sqlalchemy mysql-connector-python
Create a database.py file and add the following code:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine("mysql://user:password@localhost/dbname")
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
Creating a Database Model
Create a model.py file and add the following code:
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Movie(Base):
__tablename__ = "movies"
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
description = Column(String(200))
Creating a Database Schema
Create a schema.py file and add the following code:
from pydantic import BaseModel
from sqlalchemy import Column, Integer, String
class MovieSchema(BaseModel):
name: str
description: str
Rendering Templates
Create a templates directory and add an index.html file:
<!DOCTYPE html>
<html>
<head>
<title>Movies</title>
</head>
<body>
<h1>Movies</h1>
<ul>
{% for movie in movies %}
<li>{{ movie.name }} - {{ movie.description }}</li>
{% endfor %}
</ul>
</body>
</html>
Creating a Movie Form
Add the following code to index.html:
<form>
<label>Name:</label>
<input type="text" name="name"><br><br>
<label>Description:</label>
<textarea name="description"></textarea><br><br>
<input type="submit" value="Submit">
</form>
Updating Movies
Create a patch route to update movies:
@app.patch("/movies/{id}")
async def update_movie(id: int, movie: MovieSchema):
db_movie = db.query(Movie).filter(Movie.id == id).first()
if db_movie:
db_movie.name = movie.name
db_movie.description = movie.description
db.commit()
return JSONResponse(status_code=200, content={"message": "Movie updated successfully"})
return JSONResponse(status_code=404, content={"message": "Movie not found"})
Deleting Movies
Create a delete route to delete movies:
@app.delete("/movies/{id}")
async def delete_movie(id: int):
db_movie = db.query(Movie).filter(Movie.id == id).first()
if db_movie:
db.delete(db_movie)
db.commit()
return JSONResponse(status_code=200, content={"message": "Movie deleted successfully"})
return JSONResponse(status_code=404, content={"message": "Movie not found"})