Back to all articles

Building Production-Ready Microservices with FastAPI

3 min read

Building Production-Ready Microservices with FastAPI

FastAPI has become one of the most popular Python frameworks for building high-performance APIs. In this article, we'll explore how to build production-ready microservices using FastAPI's advanced features.

Why FastAPI for Microservices?

FastAPI offers several advantages that make it perfect for microservices:

  • Performance: Built on Starlette and Pydantic, it's one of the fastest Python frameworks available
  • Type Safety: Native support for Python type hints
  • Automatic Documentation: OpenAPI (Swagger) and ReDoc out of the box
  • Modern Python: Takes full advantage of Python 3.7+ features
  • Async Support: First-class support for async/await

Project Structure

├── app
│   ├── api
│   │   ├── __init__.py
│   │   ├── v1
│   │   │   ├── __init__.py
│   │   │   └── endpoints.py
│   ├── core
│   │   ├── __init__.py
│   │   ├── config.py
│   │   └── security.py
│   ├── db
│   │   ├── __init__.py
│   │   └── session.py
│   ├── models
│   │   ├── __init__.py
│   │   └── user.py
│   └── schemas
│       ├── __init__.py
│       └── user.py
├── tests
│   └── test_api.py
└── main.py

Dependency Injection

from fastapi import Depends, FastAPI
from sqlalchemy.orm import Session

app = FastAPI()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

@app.get("/users/{user_id}")
async def read_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.id == user_id).first()
    return user

Request Validation with Pydantic

from pydantic import BaseModel, EmailStr
from typing import Optional

class UserCreate(BaseModel):
    email: EmailStr
    full_name: str
    password: str
    
class UserResponse(BaseModel):
    id: int
    email: EmailStr
    full_name: str
    is_active: bool

    class Config:
        from_attributes = True

Middleware for Production

from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

app.add_middleware(
    TrustedHostMiddleware, 
    allowed_hosts=["api.yourdomain.com"]
)

Error Handling

from fastapi import HTTPException
from fastapi.responses import JSONResponse
from fastapi.requests import Request

@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
    return JSONResponse(
        status_code=exc.status_code,
        content={
            "message": exc.detail,
            "code": exc.status_code
        }
    )

Background Tasks

from fastapi import BackgroundTasks

def process_notification(user_id: int):
    # Long-running task
    pass

@app.post("/users/")
async def create_user(
    user: UserCreate, 
    background_tasks: BackgroundTasks,
    db: Session = Depends(get_db)
):
    db_user = User(**user.dict())
    db.add(db_user)
    db.commit()
    
    background_tasks.add_task(process_notification, db_user.id)
    return db_user

Testing

from fastapi.testclient import TestClient
import pytest

client = TestClient(app)

def test_read_user():
    response = client.get("/users/1")
    assert response.status_code == 200
    assert response.json()["id"] == 1

Conclusion

FastAPI provides all the tools needed to build robust, scalable microservices. By following these patterns and best practices, you can create maintainable services that are ready for production use.

Remember to:

  • Use type hints consistently
  • Implement proper error handling
  • Write comprehensive tests
  • Use dependency injection
  • Implement proper validation
  • Configure appropriate middleware

In the next article, we'll explore how to deploy FastAPI applications using Nginx and Docker.