FastAPI is a modern web framework for building APIs with Python. It provides automatic API documentation, type validation using Pydantic, and high performance based on Starlette and Pydantic.
Why FastAPI
FastAPI provides several advantages over other Python web frameworks. It offers automatic interactive API documentation with Swagger UI and ReDoc, available at /docs and /redoc endpoints.
It’s based on open standards like JSON Schema and OpenAPI, making it easy to integrate with other tools. The use of Python type hints provides excellent code editor auto-complete features.
FastAPI includes built-in security and authentication support for HTTP Basic, OAuth2, API keys in headers, query parameters, and cookies. It supports testing with pytest, WebSockets, GraphQL, in-process background tasks, and startup and shutdown events.
Setup
To get started, create a new project directory and set up a virtual environment:
mkdir project_name
cd project_name
python3 -m venv .venv
source .venv/bin/activate
pip install fastapi
pip install uvicorn
Uvicorn is an ASGI server that runs FastAPI applications. The virtual environment isolates your project dependencies.
Creating Your First API
Create a file named main.py:
from fastapi import FastAPI
# Creating instance
app = FastAPI()
@app.get('/')
def index():
return "hey"
The four essential steps are: import FastAPI, create an instance, define a function, and decorate it with a route.
Running the Application
Run the application using uvicorn:
uvicorn main:app --reload
The command format is uvicorn filename:instance_name --reload. The --reload flag enables auto-reload during development.
If your instance is named myapp, the command would be uvicorn main:myapp --reload. If your file is named mehedi.py, the command would be uvicorn mehedi:app --reload.
The application will be available at http://127.0.0.1:8000. Without defining routes, you’ll see a “Not Found” response.
Understanding Routes
The function name under the decorator doesn’t matter. You can use the same function name for different decorators:
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def home():
return {"data": "this is from / path"}
@app.get("/about")
def about():
return {"data": "this is from /about path"}
Only the decorator matters for routing. The decorator structure is @instance.operation('path'), where @app is the instance, get() is the HTTP operation, and '/about' is the path.
The function is called a path operation function, which defines the operation to perform on the route.
Dynamic Routes
For dynamic routing, use {} in the path and accept the variable in the path operation function:
from fastapi import FastAPI
app = FastAPI()
@app.get("/blog/{id}")
def show(id):
return {"data": id}
FastAPI reads code line by line, so route order matters. Specific routes should come before dynamic routes:
@app.get('/blog/unpublished')
def unpublished():
return {'data': 'all unpublished blogs'}
@app.get('/blog/{id}')
def show(id: int):
return {'data': id}
If the dynamic route comes first, FastAPI will try to parse “unpublished” as an integer and return an error.
Type Hints and Validation
Type hints enable automatic type conversion and validation. FastAPI uses Pydantic for validation:
@app.get('/blog/{id}')
def show(id: int):
return {'data': id}
If the value can be converted to an integer, it will be. If not, FastAPI returns a validation error with details about what went wrong.
Query Parameters
Query parameters allow clients to send additional data with requests:
@app.get('/blog')
def index(limit: int, published: bool):
if published:
return {'data': f'blog list {published} blogs from the db'}
else:
return {'data': 'all the blogs from db'}
Without type hints, string values like “false” would be considered truthy. Type hints ensure proper type conversion.
To make parameters optional, use default values:
@app.get('/blog')
def index(limit: int = 10, published: bool = True):
# ...
For optional parameters that might not be provided, use Optional from typing:
from typing import Optional
@app.get('/blog')
def index(limit: int, published: bool, sort: Optional[str] = None):
# ...
FastAPI identifies query parameters by checking the decorator’s path parameters first. Any remaining parameters in the function signature are treated as query parameters.
Request Bodies
To accept data in request bodies, use Pydantic models:
from pydantic import BaseModel
class Blog(BaseModel):
title: str
body: str
published: Optional[bool]
@app.post('/blog')
def create_blog(request: Blog):
return {'data': f"Blog is created with {request.title}"}
Pydantic models automatically validate request bodies and provide type safety. The API documentation will show the required body structure.
Automatic API Documentation
FastAPI automatically generates interactive API documentation. Visit /docs for Swagger UI or /redoc for ReDoc documentation. These interfaces allow you to test your API directly from the browser.
Summary
FastAPI makes it easy to build APIs with Python. By using type hints and Pydantic models, you get automatic validation, documentation, and type safety. The framework handles routing, request parsing, and response generation, allowing you to focus on your application logic.
The key concepts are understanding how routes work, using type hints for validation, handling query parameters and request bodies, and leveraging the automatic documentation features.