Build complex web APIs with FastAPI
Building complex Web APIs usually involve multiple aspects, including good architectural design, clear routing organization, data verification and processing, security measures, performance optimization, etc. The key to building complex web APIs with FastAPI is to take advantage of the tools and features it provides while following software engineering best practices. Here is a detailed guide to help you build a complex and efficient web API using FastAPI.
1. Project Structure
Create a reasonable folder structure for your project, which helps with the organization and maintenance of your code. For example:
my_project/ ├── app/ │ ├── __init__.py │ ├── │ ├── │ ├── │ ├── │ ├── routers/ │ │ ├── __init__.py │ │ ├── │ │ └── │ ├── services/ │ │ ├── __init__.py │ │ ├── item_service.py │ │ └── user_service.py │ ├── │ └── └── tests/ ├── __init__.py └── test_main.py
2. Dependency management
useOr more modern
poetry
To manage project dependencies. Ensure that all libraries required for development and production environments are listed.
# Use poetry to initialize the project and add dependenciespoetry init poetry add fastapi uvicorn sqlalchemy alembic bcrypt passlib[bcrypt] pydantic email-validator
3. Configuration Management
Use environment variables or configuration files to manage different settings of your application (such as database connection strings, keys, etc.). You can use Pydantic'sBaseSettings
kind.
# from pydantic import BaseSettings class Settings(BaseSettings): app_name: str = "My Complex API" admin_email: str items_per_user: int = 50 secret_key: str algorithm: str = "HS256" access_token_expire_minutes: int = 30 class Config: env_file = ".env" settings = Settings()
4. Database integration
Select the right ORM (such as SQLAlchemy) and integrate with FastAPI. Create a database model and consider using Alembic for database migration.
# from sqlalchemy import create_engine from import declarative_base from import sessionmaker SQLALCHEMY_DATABASE_URL = "sqlite:///./" engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) Base = declarative_base() def get_db(): db = SessionLocal() try: yield db finally: ()
5. Define the model and pattern
Create data models for mapping to database tables, and Pydantic models for verification of request bodies and responses.
# from sqlalchemy import Column, Integer, String from .database import Base class Item(Base): __tablename__ = "items" id = Column(Integer, primary_key=True, index=True) name = Column(String, index=True) description = Column(String, index=True) # from pydantic import BaseModel class ItemCreate(BaseModel): name: str description: str = None class Item(BaseModel): id: int name: str description: str = None class Config: orm_mode = True
6. Service layer
In order to maintain the simplicity of the controller (routing processing function), business logic is separated into the service layer.
# services/item_service.py from typing import List from import Session from ..models import Item as ItemModel from ..schemas import ItemCreate, Item def get_items(db: Session, skip: int = 0, limit: int = 10) -> List[Item]: return (ItemModel).offset(skip).limit(limit).all() def create_item(db: Session, item: ItemCreate) -> Item: db_item = ItemModel(**()) (db_item) () (db_item) return db_item
7. Routing grouping
Group relevant path operations into different router modules to improve code readability and maintainability.
# routers/ from fastapi import APIRouter, Depends from import Session from ... import schemas, services from ...dependencies import get_db router = APIRouter() @("/", response_model=List[]) def read_items(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)): items = services.get_items(db, skip=skip, limit=limit) return items @("/", response_model=) def create_item(item: , db: Session = Depends(get_db)): return services.create_item(db=db, item=item)
8. Main application portal
Import and include individual routers in the main application file.
# from fastapi import FastAPI from .routers import items, users app = FastAPI() app.include_router() app.include_router()
9. Security
Implement authentication and authorization mechanisms, such as using JWT Token for user authentication.
# from datetime import datetime, timedelta from jose import JWTError, jwt from fastapi import Depends, HTTPException, status from import OAuth2PasswordBearer from . import models, schemas, config oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") async def get_current_user(token: str = Depends(oauth2_scheme)): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = (token, .secret_key, algorithms=[]) username: str = ("sub") if username is None: raise credentials_exception token_data = (username=username) except JWTError: raise credentials_exception user = get_user(db, username=token_data.username) if user is None: raise credentials_exception return user
10. Test
Write unit tests and integration tests to make sure your API works as expected. FastAPI provides convenient testing clientsTestClient
。
# tests/test_main.py from import TestClient from my_project. import app client = TestClient(app) def test_read_main(): response = ("/") assert response.status_code == 200 assert () == {"message": "Hello World"}
11. Deployment
Consider containerizing your application with Docker and automatically deploying it to the cloud platform or server via a CI/CD pipeline.
# Dockerfile FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9 COPY ./app /app WORKDIR /app RUN pip install --no-cache-dir -r CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
Summarize
The above steps allow you to use FastAPI to build complex web APIs.
FastAPI supported tools
FastAPI provides a wealth of tools and features that make it easier to develop efficient, secure and easy to maintain Web APIs. In addition to core features, there are some important tools and features that can help you build more powerful applications. Here are some important tools and features of FastAPI:
1. Dependency injection system
FastAPI has built-in a powerful and flexible dependency injection system, which allows you to easily manage and reuse code logic such as authentication, database connections, etc.
from fastapi import Depends, FastAPI app = FastAPI() async def get_db(): db = DBSession() try: yield db finally: () @("/items/") async def read_items(db: Session = Depends(get_db)): items = (Item).all() return items
2. Pydantic model
Pydantic is a data verification library that allows you to define data models and automatically process data parsing and verification. FastAPI uses Pydantic to ensure that request bodies, query parameters, and other inputs meet the expected format.
from pydantic import BaseModel class Item(BaseModel): name: str description: str = None price: float tax: float = None
3. Middleware
Middleware is code executed before the request reaches the routing processing function or after the response is sent to the client. You can use middleware to add common behaviors such as logging, authentication, CORS processing, etc.
from import CORSMiddleware app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )
4. Exception handling
FastAPI provides a built-in exception handling mechanism and allows you to customize exception handlers to handle specific types of errors.
from fastapi import Request, status from import JSONResponse from import RequestValidationError @app.exception_handler(RequestValidationError) async def validation_exception_handler(request: Request, exc: RequestValidationError): return JSONResponse( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content={"detail": (), "body": }, )
5. Background task
If you need to continue performing certain operations (such as sending an email) after returning a response, you can use the background task.
from fastapi import BackgroundTasks def write_log(message: str): with open("", mode="a") as log: (message) @("/send-notification/{email}") async def send_notification(email: str, background_tasks: BackgroundTasks): background_tasks.add_task(write_log, f"Notification sent to {email}\n") return {"message": "Notification sent in the background"}
6. Static files and templates
FastAPI supports serving static files (such as HTML, CSS, JavaScript files) as well as rendering templates, which are useful for creating complete web applications.
from import StaticFiles from import Jinja2Templates ("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates") @("/") async def read_root(request: Request): return ("", {"request": request})
7. WebSocket Support
FastAPI supports WebSocket connections, which is useful for real-time two-way communications, such as chat applications or real-time updated data presentation.
from fastapi import WebSocket, WebSocketDisconnect @("/ws") async def websocket_endpoint(websocket: WebSocket): await () try: while True: data = await websocket.receive_text() await websocket.send_text(f"Message text was: {data}") except WebSocketDisconnect: pass
8. Environment variables and configuration management
usepydantic
ofBaseSettings
Classes to manage application configuration and environment variables, which helps separate configuration and code.
from pydantic import BaseSettings class Settings(BaseSettings): app_name: str = "Awesome API" admin_email: str items_per_user: int = 50 class Config: env_file = ".env" settings = Settings()
9. Test tools
FastAPI provides convenient testing tools, including testing clientsTestClient
and emulators to help you quickly test the API locally.
from import TestClient client = TestClient(app) def test_read_main(): response = ("/") assert response.status_code == 200 assert () == {"message": "Hello World"}
10. OpenAPI and Swagger UI
FastAPI automatically generates OpenAPI specifications and provides an interactive API documentation interface (Swagger UI and ReDoc). This not only facilitates developers to debug the API, but also facilitates users to understand how to use your API.
# Automatically generate and provide interactive documents# Visit http://127.0.0.1:8000/doc or http://127.0.0.1:8000/redoc
11. Rate Limitation
While FastAPI itself does not directly provide rate limiting functionality, this feature can be implemented through middleware or other extensions to prevent abuse or protect server resources.
from fastapi import FastAPI, HTTPException, status from import Middleware from import TrustedHostMiddleware app = FastAPI(middleware=[ Middleware(TrustedHostMiddleware, allowed_hosts=[""]) ]) # Or use third-party libraries such as fastapi-limiter to implement rate limiting
Together, these tools and features form a powerful and flexible ecosystem of FastAPI, allowing developers to build modern web APIs more efficiently.
FastAPI routing operations
FastAPI supports all standard HTTP methods (also known as "routing operations" or "HTTP verbs") that define the type of interaction between the client and the server. Here are the main routing operations supported by FastAPI:
1. GET
Used to request information from the server, usually used to query resources.
@("/items/{item_id}") async def read_item(item_id: int): return {"item_id": item_id}
2. POST
Used to submit data to a specified resource, often used to create new resources or send form data.
@("/items/") async def create_item(item: Item): return item
3. PUT
Used to update existing resources, usually the entire resource will be replaced.
@("/items/{item_id}") async def update_item(item_id: int, item: Item): return {"item_id": item_id, "item": item}
4. DELETE
Used to delete the specified resource.
@("/items/{item_id}") async def delete_item(item_id: int): return {"item_id": item_id}
5. PATCH
Used to partially update the resource and modify only the specified fields.
@("/items/{item_id}") async def patch_item(item_id: int, item: ItemUpdate): return {"item_id": item_id, "item": item}
6. OPTIONS
Communication options used to describe the target resource. It returns a list of methods supported by the server.
@("/items/") async def describe_options(): return {"Allow": "GET, POST, PUT, DELETE, PATCH, OPTIONS"}
7. HEAD
Similar to a GET request, but does not return the message body and is only used to obtain response header information.
@("/items/{item_id}") async def head_item(item_id: int): # Process logic, but will not return the response body pass
8. TRACE
Used to echo the request received by the server, mainly for testing or diagnosis.
@("/trace") async def trace_request(): return {"method": "TRACE"}
Routing parameters
In addition to the above HTTP methods, FastAPI also allows you to define path parameters, query parameters, request bodies, etc. to handle different request scenarios more flexibly.
Path parameters
Define parameters directly in the path, such as/items/{item_id}
Initem_id
。
@("/items/{item_id}") async def read_item(item_id: int): return {"item_id": item_id}
Query parameters
Pass parameters through the query string of the URL, for example/items/?skip=0&limit=10
。
@("/items/") async def read_items(skip: int = 0, limit: int = 10): return {"skip": skip, "limit": limit}
Request body
Use the Pydantic model to parse and verify JSON request bodies.
from pydantic import BaseModel class Item(BaseModel): name: str description: str = None price: float tax: float = None @("/items/") async def create_item(item: Item): return item
Extra Features
-
Path operation function: Can be a synchronous function (
def
) or asynchronous function (async def
), choose according to your needs. - Dependency injection: Dependencies can be added in the path operation function to facilitate sharing of state or performing preprocessing logic.
- middleware: Add additional behavior to all requests, such as logging, authentication, etc.
- Custom response: You can return different types of responses, including JSONResponse, HTMLResponse, etc.
- WebSocket: FastAPI also supports WebSocket connections and can be used to implement real-time two-way communication.
The above are the main routing operations supported by FastAPI. FastAPI is designed to not only support standard HTTP methods, but also provide powerful tools to help developers build modern web APIs.
Summarize
This is the end of this article about how python builds complex web APIs through FastAPI. For more related content on python FastAPI, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!