FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. In this guide, we'll walk through setting up FastAPI and implementing all the basic CRUD operations.
Installation and Setup
First, let's set up a virtual environment and install FastAPI:
Create a virtual environment
python -m venv venv
Activate the virtual environment
On Windows:
venv\Scripts\activate
On macOS/Linux:
source venv/bin/activate
Install FastAPI with all dependencies
pip install "fastapi[standard]"
Basic FastAPI Application
Let's create a movie API example instead of books. Create a file called app.py
:
from fastapi import FastAPI
app = FastAPI()
MOVIES = [
{"title": "Inception", "director": "Christopher Nolan", "genre": "sci-fi"},
{"title": "The Shawshank Redemption", "director": "Frank Darabont", "genre": "drama"},
{"title": "The Dark Knight", "director": "Christopher Nolan", "genre": "action"},
{"title": "Pulp Fiction", "director": "Quentin Tarantino", "genre": "crime"},
{"title": "Parasite", "director": "Bong Joon-ho", "genre": "drama"}
]
Running the Application
Start the server with:
uvicorn app:app --reload
The --reload
flag enables auto-reload when you make code changes.
Visit http://127.0.0.1:8000/docs to see the interactive Swagger UI documentation.
Implementing CRUD Operations
1. GET Request (Read All)
@app.get('/movies')
async def read_all_movies():
return MOVIES
This endpoint returns the entire list of movies. The @app.get
decorator defines a GET request at the /movies
endpoint
2. Path Parameters (Read One)
@app.get('/movies/{movie_title}')
async def get_movie(movie_title: str):
for movie in MOVIES:
if movie.get("title").casefold() == movie_title.casefold():
return movie
return {"error": "Movie not found"}
This endpoint retrieves a single movie by its title. The {movie_title} in the path is a path parameter that captures the movie title from the URL.
3. Query Parameters (Filtering)
@app.get('/movies/')
async def read_movies_by_genre(genre: str):
movies_to_return = []
for movie in MOVIES:
if movie.get('genre').casefold() == genre.casefold():
movies_to_return.append(movie)
return movies_to_return if movies_to_return else {"message": "No movies found in this genre"}
This endpoint filters movies by genre using a query parameter. The genre parameter is passed in the URL as a query string (e.g., /movies/?genre=drama).
4. POST Request (Create)
from fastapi import Body
@app.post('/movies/create_movie')
async def create_movie(new_movie=Body()):
MOVIES.append(new_movie)
return {"message": "Movie added successfully", "movie": new_movie}
This endpoint adds a new movie to the list. The Body dependency extracts the JSON body from the request, which contains the new movie's details.
5. PUT Request (Update)
@app.put('/movies/update_movie')
async def update_movie(updated_movie=Body()):
for i in range(len(MOVIES)):
if MOVIES[i].get('title').casefold() == updated_movie.get('title').casefold():
MOVIES[i] = updated_movie
return {"message": "Movie updated successfully"}
return {"error": "Movie not found"}
This endpoint updates an existing movie's details. It searches for the movie by title and replaces it with the updated movie data.
6. DELETE Request
@app.delete('/movies/delete_movie/{movie_title}')
async def delete_movie(movie_title: str):
for i in range(len(MOVIES)):
if MOVIES[i].get('title').casefold() == movie_title.casefold():
deleted_movie = MOVIES.pop(i)
return {"message": "Movie deleted successfully", "deleted_movie": deleted_movie}
return {"error": "Movie not found"}
This endpoint deletes a movie by its title. It searches for the movie and removes it from the list if found.
Best Practices
- Always use virtual environments
- Organize your code with routers as your app grows
- Add input validation using Pydantic models
- Implement proper error handling
- Consider adding authentication for production APIs