Proč FastAPI v roce 2026

FastAPI se během několika let změnilo z experimentálního projektu na referenční rámec pro API Python ve výrobě. Podle průzkumu Python Developers Survey 2024 se jedná o druhý framework Python web podle difúze (38 %), překonán pouze Django. Důvody jsou konkrétní: výkon srovnatelné s Node.js a Go for I/O-bound workloads, zero-boilerplate data validation with Pydantic v2 a dokumentace OpenAPI automaticky generovaná z kódu.

Tajemství je architektonické: FastAPI je postaveno na Hvězdičky (rámec ASGI) e Pydantický (validace s jádrem Rust). Nepřidává zbytečné abstrakce – každý prvek má přesný technický důvod.

Co se naučíte

  • Instalace a spuštění prvního FastAPI serveru za 5 minut
  • Jak se tipy typu Python stávají ověřováním, serializací a dokumentací
  • Parametry cesty, parametry dotazů a těla požadavků s Pydantic
  • Uživatelské rozhraní Swagger a ReDoc: Procházení automaticky generované dokumentace
  • Stavové kódy, modely odezvy a základní zpracování chyb
  • Struktura skutečného projektu FastAPI (nejen jeden soubor)

Instalace a první server

FastAPI vyžaduje Python 3.8+, ale pro lepší výkon doporučujeme 3.11+ asyncio a nové funkce tipů typu. Uvicorn je server ASGI doporučeno pro místní rozvoj.

# Ambiente virtuale (sempre, mai installare globalmente)
python -m venv .venv
source .venv/bin/activate  # Linux/Mac
# .venv\Scripts\activate  # Windows

# Installazione dipendenze core
pip install fastapi uvicorn[standard]

# Per sviluppo aggiungere anche:
pip install httpx pytest pytest-asyncio

# Verifica installazione
python -c "import fastapi; print(fastapi.__version__)"
# 0.115.x

Minimální možný server. Uložit toto jako main.py:

# main.py - Il server FastAPI piu semplice possibile
from fastapi import FastAPI

# Crea l'istanza dell'applicazione
# title e description appaiono nella documentazione Swagger
app = FastAPI(
    title="La Mia API",
    description="API costruita con FastAPI e Python type hints",
    version="1.0.0",
)

# Decorator che registra la route GET /
@app.get("/")
def read_root():
    # Il dict viene automaticamente serializzato in JSON
    return {"message": "Hello, FastAPI!", "status": "running"}

# Avvio con: uvicorn main:app --reload
# main = nome del file, app = variabile FastAPI, --reload = hot reload
# Avvia il server con hot reload (ricrea il server ad ogni modifica)
uvicorn main:app --reload

# Output:
# INFO:     Will watch for changes in these directories: ['/path/to/project']
# INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
# INFO:     Started reloader process [12345]
# INFO:     Started server process [12346]
# INFO:     Waiting for application startup.
# INFO:     Application startup complete.

OTEVŘENO http://127.0.0.1:8000/docs zobrazit vygenerované uživatelské rozhraní Swagger automaticky. Nic jste nenakonfigurovali: FastAPI načetlo anotace kódu a vytvořil kompletní dokumentaci.

Zadejte Hints jako API kontrakt

Nejvýkonnější funkcí FastAPI je použití tipů typu Python jako např Definice smlouvy API. Každý anotovaný parametr se automaticky stane: ověřeno, zdokumentováno a serializováno. Nulový dodatečný standardní kód.

# routes/users.py - Esempi di parametri con type hints
from fastapi import FastAPI, Path, Query, HTTPException
from typing import Optional
from pydantic import BaseModel, EmailStr, Field
from datetime import datetime

app = FastAPI()

# --- PATH PARAMETERS ---
# Il tipo int fa si che FastAPI validi che userId sia un intero
@app.get("/users/{user_id}")
def get_user(
    user_id: int,  # Path parameter: automaticamente estratto dall'URL
):
    if user_id <= 0:
        raise HTTPException(status_code=400, detail="user_id must be positive")
    return {"user_id": user_id, "name": f"User {user_id}"}

# Path con validazione avanzata tramite Path()
@app.get("/items/{item_id}")
def get_item(
    item_id: int = Path(
        title="The ID of the item",
        description="Must be a positive integer",
        ge=1,       # greater than or equal to 1
        le=1000,    # less than or equal to 1000
    ),
):
    return {"item_id": item_id}

# --- QUERY PARAMETERS ---
# Parametri con default = opzionali, senza default = obbligatori
@app.get("/search")
def search_users(
    q: str,                          # Obbligatorio (no default)
    page: int = 1,                   # Opzionale con default
    limit: int = Query(default=10, ge=1, le=100),  # Con validazione
    active_only: bool = True,        # Bool viene da "true"/"false" nella query string
    role: Optional[str] = None,      # Opzionale, None se non fornito
):
    return {
        "query": q,
        "page": page,
        "limit": limit,
        "active_only": active_only,
        "role": role,
    }
    # GET /search?q=mario&page=2&limit=20&active_only=false&role=admin

Vyžádejte si tělo s Pydantickými modely

Pro data v těle požadavku POST/PUT/PATCH se používají šablony Pydantic. FastAPI automaticky deserializuje příchozí JSON, ověří jej proti šabloně, a zpřístupní jej jako typovaný objekt Pythonu.

# models/user.py - Definizione dei modelli con Pydantic v2
from pydantic import BaseModel, EmailStr, Field, field_validator
from typing import Optional
from enum import Enum

class UserRole(str, Enum):
    admin = "admin"
    editor = "editor"
    viewer = "viewer"

# Modello per la creazione di un utente (in input)
class UserCreate(BaseModel):
    name: str = Field(
        min_length=2,
        max_length=100,
        description="Full name of the user",
        examples=["Mario Rossi"],
    )
    email: EmailStr  # Validazione email inclusa in Pydantic
    role: UserRole = UserRole.viewer  # Default al valore meno privilegiato
    age: Optional[int] = Field(default=None, ge=0, le=150)

    # Validator personalizzato (Pydantic v2 syntax)
    @field_validator("name")
    @classmethod
    def name_must_contain_space(cls, v: str) -> str:
        if " " not in v:
            raise ValueError("name must contain at least first and last name")
        return v.strip()

# Modello per la risposta (include campi generati dal server)
class UserResponse(BaseModel):
    id: int
    name: str
    email: EmailStr
    role: UserRole
    created_at: str  # ISO 8601

# Route POST che usa i modelli
@app.post(
    "/users",
    response_model=UserResponse,  # Definisce la struttura della risposta
    status_code=201,               # HTTP 201 Created
    summary="Create a new user",
    tags=["users"],
)
def create_user(user: UserCreate):
    # user e gia validato e typed come UserCreate
    # FastAPI ha deserializzato il JSON e verificato tutti i vincoli
    new_user = {
        "id": 42,  # In realta verrebbe dal database
        "name": user.name,
        "email": user.email,
        "role": user.role.value,
        "created_at": "2026-06-01T10:00:00Z",
    }
    return new_user
    # Solo i campi di UserResponse vengono inclusi nella risposta
    # (response_model filtra automaticamente campi extra come password hash)

Zpracování chyb pomocí HTTPException

FastAPI mapuje výjimky do strukturovaných HTTP odpovědí. Používá standardní vzor HTTPException pro očekávané chyby a obslužnou rutinu globálních výjimek neočekávané chyby.

# Errori standard con HTTPException
from fastapi import HTTPException, status

@app.get("/users/{user_id}", response_model=UserResponse)
def get_user(user_id: int):
    user = db.find_user(user_id)  # Ipotetica funzione DB

    if user is None:
        # status.HTTP_404_NOT_FOUND = 404 (uso le costanti, piu leggibile)
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"User with id {user_id} not found",
        )

    return user

# Exception handler globale per errori non gestiti
from fastapi import Request
from fastapi.responses import JSONResponse

@app.exception_handler(Exception)
async def generic_exception_handler(request: Request, exc: Exception):
    # Log l'errore (NON esporre il dettaglio in produzione)
    import logging
    logging.error(f"Unhandled exception: {exc}", exc_info=True)

    return JSONResponse(
        status_code=500,
        content={"detail": "Internal server error"},
    )

Struktura reálného projektu

Singl main.py je to dobré pro tutoriály, ale ne pro skutečný projekt. Doporučená struktura rozděluje obavy do soudržných modulů:

# Struttura consigliata per un progetto FastAPI medio
my_api/
├── app/
│   ├── __init__.py
│   ├── main.py              # Entry point: crea l'app FastAPI e include i router
│   ├── config.py            # Configurazione (env vars, Settings con Pydantic)
│   ├── database.py          # Connessione DB, session factory
│   ├── models/
│   │   ├── __init__.py
│   │   ├── user.py          # SQLAlchemy ORM models
│   │   └── item.py
│   ├── schemas/             # Pydantic models (request/response)
│   │   ├── __init__.py
│   │   ├── user.py          # UserCreate, UserUpdate, UserResponse
│   │   └── item.py
│   ├── routers/             # APIRouter per ogni dominio
│   │   ├── __init__.py
│   │   ├── users.py         # /users endpoints
│   │   └── items.py         # /items endpoints
│   ├── services/            # Business logic (separata dai router)
│   │   ├── user_service.py
│   │   └── item_service.py
│   └── dependencies.py      # Depends() condivise (auth, DB session)
├── tests/
│   ├── conftest.py
│   ├── test_users.py
│   └── test_items.py
├── alembic/                 # Migrations DB
├── pyproject.toml
└── docker-compose.yml
# app/main.py - Entry point con router modulari
from fastapi import FastAPI
from app.routers import users, items
from app.config import get_settings

settings = get_settings()

app = FastAPI(
    title=settings.APP_NAME,
    version=settings.APP_VERSION,
    docs_url="/docs" if settings.DEBUG else None,  # Disabilita docs in produzione
    redoc_url="/redoc" if settings.DEBUG else None,
)

# Include i router con prefisso e tag per la documentazione
app.include_router(users.router, prefix="/users", tags=["users"])
app.include_router(items.router, prefix="/items", tags=["items"])

@app.get("/health", tags=["system"])
def health_check():
    return {"status": "healthy", "version": settings.APP_VERSION}

Dokumentace OpenAPI: Swagger a ReDoc

FastAPI automaticky generuje dvě interaktivní dokumentační rozhraní, která můžete navštívit během vývoje:

  • Uživatelské rozhraní Swagger (/docs): interaktivní rozhraní pro testování API přímo z prohlížeče. Podporuje ověřování, tělo JSON, parametry dotazu.
  • ReDoc (/redoc): čitelná dokumentace, ideální pro sdílet se svým týmem nebo spotřebiteli API.
  • OpenAPI JSON (/openapi.json): strojově čitelné schéma slouží ke generování klientů SDK v libovolném jazyce.
# Arricchire la documentazione con metadata aggiuntivi
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi

app = FastAPI()

# Override del schema OpenAPI per aggiungere security schemes e metadata
def custom_openapi():
    if app.openapi_schema:
        return app.openapi_schema

    openapi_schema = get_openapi(
        title="My API",
        version="2.0.0",
        description="Descrizione lunga dell'API con **markdown** supportato",
        terms_of_service="https://example.com/terms",
        contact={
            "name": "Federico Calo",
            "url": "https://federicocalo.dev",
            "email": "info@federicocalo.dev",
        },
        license_info={
            "name": "MIT",
            "url": "https://opensource.org/licenses/MIT",
        },
        routes=app.routes,
    )

    # Aggiungi Bearer token authentication
    openapi_schema["components"]["securitySchemes"] = {
        "BearerAuth": {
            "type": "http",
            "scheme": "bearer",
            "bearerFormat": "JWT",
        }
    }

    app.openapi_schema = openapi_schema
    return app.openapi_schema

app.openapi = custom_openapi

Dokumentace ve výrobě

Vždy deaktivujte Swagger UI a ReDoc v produkci nastavením docs_url=None e redoc_url=None v konstruktoru FastAPI. Interaktivní dokumentace odhaluje vnitřní strukturu API a může použít k prozkoumání nezdokumentovaných koncových bodů. Koncový bod /openapi.json musí být chráněny stejným způsobem.

Konfigurace pomocí Pydantic Settings

Správný způsob, jak zpracovat konfiguraci ve FastAPI, je použít pydantic-settings který automaticky čte proměnné prostředí s ověřením typu:

# app/config.py - Configurazione type-safe con pydantic-settings
# pip install pydantic-settings
from pydantic_settings import BaseSettings, SettingsConfigDict
from functools import lru_cache

class Settings(BaseSettings):
    # Valori letti da variabili d'ambiente (case insensitive)
    APP_NAME: str = "My FastAPI App"
    APP_VERSION: str = "1.0.0"
    DEBUG: bool = False

    # Database
    DATABASE_URL: str  # Obbligatorio: fallisce se non presente
    DB_POOL_SIZE: int = 10
    DB_MAX_OVERFLOW: int = 20

    # Secrets
    SECRET_KEY: str  # Obbligatorio
    ACCESS_TOKEN_EXPIRE_MINUTES: int = 30

    # CORS
    ALLOWED_ORIGINS: list[str] = ["http://localhost:3000"]

    model_config = SettingsConfigDict(
        env_file=".env",           # Legge da .env se presente
        env_file_encoding="utf-8",
        case_sensitive=False,      # DATABASE_URL = database_url
    )

# lru_cache evita di rileggere il file .env ad ogni richiesta
@lru_cache
def get_settings() -> Settings:
    return Settings()

# Uso nelle route tramite Depends()
from fastapi import Depends

@app.get("/info")
def app_info(settings: Settings = Depends(get_settings)):
    return {
        "name": settings.APP_NAME,
        "version": settings.APP_VERSION,
        "debug": settings.DEBUG,
    }

Závěry a další kroky

FastAPI kombinuje tři funkce, které se obecně vylučují: rychlost vývoje, typová bezpečnost a výkon. Typové rady nejsou dekorativní – slouží k ověření, dokumentaci a automatickou serializaci. To drasticky redukuje kód standardní ve srovnání s Flask nebo Django REST Framework.

Dalším krokem je pochopení asynchronního modelu, díky kterému je FastAPI rychlé Úlohy vázané na I/O: jak fungují asyncio, smyčky událostí a korutiny a kdy je použít async def vs def normální.

Python FastAPI a Async Web Series

  • Článek 1 (tento): Nastavení, tipy pro typy a vlastní dokumentace OpenAPI
  • Článek 2: Async/Await v Pythonu: smyčky událostí, korutiny a souběžnost vázaná na I/O
  • Článek 3: Pydantic v2: Advanced Validation, BaseModel a TypeAdapter
  • Článek 4: Vložení závislosti: Vzor pro čistý a testovatelný kód
  • Článek 5: Async Database s SQLAlchemy 2.0 a Alembic