Skip to content

Construire un projet FastAPI

FastAPI est un framework web Python moderne et performant, basé sur les annotations de type Python et Pydantic. Il génère automatiquement la documentation OpenAPI.

Initialisation d'un projet

Utiliser uv pour gérer le projet Python et ses dépendances :

shell
uv init my-api && cd my-api
uv add "fastapi[standard]"

Cela génère un fichier pyproject.toml avec les métadonnées du projet et un fichier uv.lock verrouillant les dépendances.

TIP

Pour lancer le serveur de développement :

shell
uv run fastapi dev

Structure du projet

cf. Architecture de dossiers

txt
├── app
│   ├── __init__.py
│   ├── main.py                # Point d'entrée FastAPI
│   ├── config.py              # Configuration (variables d'env)
│   ├── models
│   │   ├── __init__.py
│   │   └── cat.py             # Modèles SQLAlchemy / Tortoise
│   ├── schemas
│   │   ├── __init__.py
│   │   └── cat.py             # Schémas Pydantic
│   ├── routers
│   │   ├── __init__.py
│   │   └── cats.py            # Routes /cats
│   ├── services
│   │   ├── __init__.py
│   │   └── cats.py            # Logique métier
│   └── utils
│       ├── __init__.py
│       └── logger.py
├── tests
│   ├── __init__.py
│   └── test_cats.py
├── pyproject.toml
├── uv.lock
└── Dockerfile

Conventions

Validation avec Pydantic

La validation des données entrantes et sortantes se fait avec des modèles Pydantic :

python
from pydantic import BaseModel, Field


class CatBase(BaseModel):
    name: str = Field(min_length=1, description="Nom du chat")
    age: int = Field(ge=0, description="Âge du chat")


class CatCreate(CatBase):
    pass


class CatResponse(CatBase):
    id: int

    model_config = {"from_attributes": True}

Routes (Routers)

Utiliser les APIRouter pour organiser les routes par domaine :

python
from fastapi import APIRouter, HTTPException, status

from app.schemas.cat import CatCreate, CatResponse
from app.services.cats import CatsService

router = APIRouter(prefix="/cats", tags=["cats"])


@router.get("/", response_model=list[CatResponse])
async def get_cats():
    return await CatsService.find_all()


@router.get("/{cat_id}", response_model=CatResponse)
async def get_cat(cat_id: int):
    cat = await CatsService.find_by_id(cat_id)
    if not cat:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Cat non trouvé",
        )
    return cat


@router.post("/", response_model=CatResponse, status_code=status.HTTP_201_CREATED)
async def create_cat(cat: CatCreate):
    return await CatsService.create(cat)

Enregistrer les routers dans main.py :

python
from fastapi import FastAPI

from app.routers import cats

app = FastAPI(title="Mon API", version="1.0.0")
app.include_router(cats.router)

Endpoints asynchrones

Privilégier les fonctions async pour les endpoints qui font des I/O (base de données, appels HTTP, etc.) :

python
# ✅ Bien : async pour les opérations I/O
@router.get("/cats")
async def get_cats():
    return await db.fetch_all(query)

# ✅ Bien : sync pour les opérations CPU-bound
@router.get("/compute")
def compute_something():
    return heavy_computation()

Logging

Utiliser le module logging standard de Python avec une configuration structurée et le pattern lifespan (recommandé depuis FastAPI 0.93+, @app.on_event("startup") est déprécié) :

python
import logging
from contextlib import asynccontextmanager

from fastapi import FastAPI

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger(__name__)


@asynccontextmanager
async def lifespan(app: FastAPI):
    # Code exécuté au démarrage
    logger.info("Application démarrée")
    yield
    # Code exécuté à l'arrêt
    logger.info("Application arrêtée")


app = FastAPI(lifespan=lifespan)

Gestion des erreurs

Créer des gestionnaires d'exceptions personnalisés :

python
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse


class AppException(Exception):
    def __init__(self, status_code: int, detail: str):
        self.status_code = status_code
        self.detail = detail


app = FastAPI()


@app.exception_handler(AppException)
async def app_exception_handler(request: Request, exc: AppException):
    return JSONResponse(
        status_code=exc.status_code,
        content={
            "detail": exc.detail,
            "timestamp": datetime.now(UTC).isoformat(),
        },
    )

Documentation OpenAPI

FastAPI génère automatiquement la documentation OpenAPI, accessible par défaut à :

  • Swagger UI : /docs
  • ReDoc : /redoc

Tests

Ajouter les dépendances de test :

shell
uv add --dev pytest httpx

Utiliser pytest avec le TestClient de FastAPI :

python
import pytest
from fastapi.testclient import TestClient

from app.main import app

client = TestClient(app)


def test_get_cats():
    response = client.get("/cats")
    assert response.status_code == 200
    assert isinstance(response.json(), list)


def test_create_cat():
    response = client.post("/cats", json={"name": "Minou", "age": 3})
    assert response.status_code == 201
    assert response.json()["name"] == "Minou"

Lancer les tests :

shell
uv run pytest

Dockerfile

Exemple de Dockerfile multi-stage optimisé avec uv :

dockerfile
# Build
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy

WORKDIR /app
RUN --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    uv sync --locked --no-install-project --no-dev
COPY . /app
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --locked --no-dev

# Runtime
FROM python:3.12-slim-bookworm

RUN groupadd --system --gid 999 nonroot \
 && useradd --system --gid 999 --uid 999 --create-home nonroot

COPY --from=builder --chown=nonroot:nonroot /app /app
ENV PATH="/app/.venv/bin:$PATH"
USER nonroot
WORKDIR /app

CMD ["fastapi", "run", "--host", "0.0.0.0", "app/main.py"]

Du POC à la production

cf. POC to Prod pour une checklist complète de mise en production d'un projet FastAPI.