FastAPI: nowoczesny, wydajny framework sieciowy dla Pythona

Twórz błyskawiczne API z automatycznymi dokumentacjami i bezpieczeństwem typów

Page content

FastAPI stał się jednym z najbardziej ekscytujących frameworków webowych w Pythonie do tworzenia interfejsów API, łącząc nowoczesne funkcje Pythona z wyjątkową wydajnością i doświadczeniem dewelopera.

Nie ważne, czy tworzysz mikrousługi, funkcje serverlessowe czy złożone aplikacje webowe, FastAPI oferuje narzędzia, które potrzebujesz do tworzenia gotowych do produkcji interfejsów API.

python i fastapi zamknięcie

Co to jest FastAPI?

FastAPI to nowoczesny, wysokiej wydajności framework webowy do tworzenia interfejsów API w Pythonie 3.8+ oparty na standardowych wskazówkach typów Pythona. Utworzony przez Sebastiána Ramíreza, został zaprojektowany tak, aby był łatwy w użyciu, szybki w kodowaniu i gotowy do produkcji od samego początku.

Framework opiera się na dwóch potężnych bibliotekach:

  • Starlette do routingu sieciowego i możliwości asynchronicznych
  • Pydantic do walidacji danych za pomocą wskazówek typów Pythona

To połączenie zapewnia wydajność porównywalną z Node.js i Go, jednocześnie zachowując prostotę i czytelność Pythona. FastAPI szybko zdobył popularność, z tysiącami gwiazd na GitHubie i zaakceptowaniem przez duże firmy na całym świecie.

Kluczowe funkcje, które wyróżniają FastAPI

1. Automatyczna dokumentacja API

Jedną z najbardziej kochanych funkcji FastAPI jest automatyczna, interaktywna dokumentacja API. Bazująca na standardzie OpenAPI (dawniej Swagger), FastAPI generuje dwa interfejsy dokumentacji:

  • Swagger UI na /docs - interaktywna dokumentacja, w której możesz bezpośrednio testować punkty końcowe API w przeglądarce
  • ReDoc na /redoc - alternatywna dokumentacja z czystym, trzema-panelowym projektem

Dokumentacja jest generowana automatycznie z wskazówek typów i docstringów w kodzie — nie wymaga dodatkowej konfiguracji. Oznacza to, że dokumentacja zawsze jest aktualna w stosunku do kodu.

2. Wskazówki typów i walidacja

FastAPI wykorzystuje wskazówki typów Pythona nie tylko do dokumentacji, ale również do walidacji w czasie wykonywania i serializacji. Gdy zdefiniujesz parametr punktu końcowego jako int, FastAPI automatycznie:

  • Weryfikuje, czy żądanie zawiera liczbę całkowitą
  • Konwertuje wartość z ciągu znaków na liczbę całkowitą
  • Zwraca jasne komunikaty o błędach w przypadku niepowodzenia walidacji
  • Dokumentuje typ parametru w dokumentacji API
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class User(BaseModel):
    username: str
    email: str
    age: int

@app.post("/users/")
async def create_user(user: User):
    return {"message": f"Użytkownik {user.username} został pomyślnie utworzony"}

Ten podejście pozwala na wykrywanie błędów wczesnie, zmniejsza ilość kodu do napisania i sprawia, że API jest samo-dokumentujące się.

3. Obsługa asynchroniczna

FastAPI jest zbudowany na ASGI (Asynchronous Server Gateway Interface), a nie na WSGI, co daje mu natywną obsługę async/await. To jest kluczowe dla aplikacji wysokiej wydajności, które wykonują wiele wywołań I/O (zapytań do bazy danych, żądań API, operacji plików).

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    # Operacje asynchroniczne nie blokują innych żądań
    data = await fetch_from_database(item_id)
    return data

Wsparcie asynchroniczne oznacza, że FastAPI może efektywnie obsługiwać tysiące równoległych połączeń, co czyni go idealnym do nowoczesnych aplikacji w chmurze i architektur mikrousług.

4. Wydajność

FastAPI to jeden z najszybszych frameworków Pythona, z wydajnością porównywalną do frameworków Node.js i Go. Niezależne testy wydajnościowo pokazują, że FastAPI przewyższa tradycyjne frameworki, takie jak Flask i Django, znacząco, szczególnie w przypadkach obciążeń I/O.

Szybkość pochodzi z:

  • Walidacji na poziomie C w Pydantic
  • Efektywnej implementacji asynchronicznej w Starlette
  • Minimalnego narzutu samego frameworku

Rozpoczynanie pracy z FastAPI

Instalacja FastAPI jest prosta. Gdy pracujesz nad projektami w Pythonie, posiadanie odpowiedniego menedżera pakietów Pythona ułatwia zarządzanie zależnościami. Będziesz potrzebował FastAPI i serwera ASGI, takiego jak Uvicorn:

pip install fastapi uvicorn[standard]

Oto minimalna aplikacja FastAPI:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Witaj, świecie"}

@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

Uruchom ją za pomocą:

uvicorn main:app --reload

Zwiedzaj http://localhost:8000/docs, aby zobaczyć interaktywną dokumentację API.

Budowanie gotowych do produkcji interfejsów API

Modele żądań i odpowiedzi

Definiowanie wyraźnych modeli danych jest kluczowe dla utrzymania zrównoważonych API. Przyjmowanie wzorców projektowych Pythona dla czystej architektury pomaga tworzyć dobrze strukturalizowane aplikacje:

from pydantic import BaseModel, EmailStr, Field
from typing import Optional
from datetime import datetime

class UserCreate(BaseModel):
    username: str = Field(..., min_length=3, max_length=50)
    email: EmailStr
    password: str = Field(..., min_length=8)

class UserResponse(BaseModel):
    id: int
    username: str
    email: str
    created_at: datetime
    
    class Config:
        orm_mode = True  # Pozwala Pydanticowi pracować z obiektami ORM

@app.post("/users/", response_model=UserResponse)
async def create_user(user: UserCreate):
    # Twoja logika biznesowa tutaj
    new_user = save_user_to_database(user)
    return new_user

Parametr response_model zapewnia, że FastAPI zwraca tylko określone pola, automatycznie filtrowując wrażliwe dane, takie jak hasła.

Iniekcja zależności

System iniekcji zależności FastAPI jest potężny i elegancki. Pozwala na:

  • Udostępnianie kodu między punktami końcowymi
  • Wymuszanie uwierzytelnienia/autoryzacji
  • Zarządzanie połączeniami do bazy danych
  • Obsługa złożonych zależności
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = verify_token(token)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Nieprawidłowe dane uwierzytelnienia"
        )
    return user

@app.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

Obsługa błędów

FastAPI oferuje wbudowane obsługiwane wyjątki i pozwala na niestandardowe odpowiedzi błędów:

from fastapi import HTTPException

@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id not in items_db:
        raise HTTPException(
            status_code=404,
            detail="Element nie znaleziony",
            headers={"X-Error": "Niestandardowy nagłówek"}
        )
    return items_db[item_id]

Zadania w tle

Dla operacji, które nie muszą zostać ukończone przed zwróceniem odpowiedzi:

from fastapi import BackgroundTasks

def send_email_notification(email: str, message: str):
    # Logika wysyłania e-maila
    pass

@app.post("/send-notification/")
async def send_notification(
    email: str,
    background_tasks: BackgroundTasks
):
    background_tasks.add_task(send_email_notification, email, "Witaj!")
    return {"message": "Powiadomienie zaplanowane"}

Testowanie aplikacji FastAPI

Kompleksowe testy jednostkowe w Pythonie są kluczowe dla niezawodnych API. FastAPI działa płynnie z pytestem i oferuje klienta testowego:

from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_read_main():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"message": "Witaj, świecie"}

def test_read_item():
    response = client.get("/items/42?q=test")
    assert response.status_code == 200
    assert response.json() == {"item_id": 42, "q": "test"}

Dla testowania asynchronicznych punktów końcowych:

import pytest
from httpx import AsyncClient

@pytest.mark.asyncio
async def test_async_endpoint():
    async with AsyncClient(app=app, base_url="http://test") as ac:
        response = await ac.get("/")
    assert response.status_code == 200

Integracja z bazą danych

FastAPI dobrze współpracuje z różnymi bazami danych i ORM. Oto przykład z SQLAlchemy:

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session
from fastapi import Depends

DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(bind=engine)
Base = declarative_base()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    username = Column(String, unique=True, index=True)
    email = Column(String, unique=True)

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()
    if not user:
        raise HTTPException(status_code=404, detail="Użytkownik nie znaleziony")
    return user

Opcje wdrażania

Wdrażanie w kontenerze Docker

Aplikacje FastAPI konteneryzują się łatwo. Oto gotowy do produkcji plik Dockerfile:

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Wdrażanie na AWS Lambda

FastAPI działa bardzo dobrze z platformami serverless. Gdy budujesz dwutrybowy AWS Lambda z Pythonem i Terraformem, możesz wdrożyć aplikacje FastAPI za pomocą Mangum, adaptera, który opakowuje FastAPI dla AWS Lambda:

from mangum import Mangum
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Witaj z Lambda!"}

handler = Mangum(app)

Dla bardziej złożonych wdrożeń, AWS SAM z Python PowerTools oferuje świetne narzędzia do aplikacji FastAPI.

Wdrażanie na tradycyjnym serwerze

Dla wdrożeń produkcyjnych na tradycyjnych serwerach lub Kubernetes:

# Z użyciem Gunicorn i Uvicorn workerów
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

Zaawansowane funkcje

CORS (Cross-Origin Resource Sharing)

Włącz CORS dla aplikacji前端:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://example.com"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

Obsługa WebSockets

FastAPI obsługuje WebSockets do komunikacji w czasie rzeczywistym:

from fastapi import WebSocket

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Otrzymano wiadomość: {data}")

Integracja z GraphQL

FastAPI może współpracować z GraphQL za pomocą Strawberry lub innych bibliotek GraphQL:

import strawberry
from strawberry.fastapi import GraphQLRouter

@strawberry.type
class Query:
    @strawberry.field
    def hello(self) -> str:
        return "Witaj, świecie"

schema = strawberry.Schema(query=Query)
graphql_app = GraphQLRouter(schema)

app.include_router(graphql_app, prefix="/graphql")

Praca z LLM i AI

FastAPI jest doskonały do tworzenia API zasilanych AI. Gdy ograniczasz LLM z użyciem strukturalnego wyjścia za pomocą Ollama, modele Pydantic w FastAPI dostarczają idealnych definicji schematu dla strukturalnych odpowiedzi:

from pydantic import BaseModel
from typing import List
import httpx

class SentimentResponse(BaseModel):
    sentiment: str
    confidence: float
    keywords: List[str]

@app.post("/analyze-sentiment/", response_model=SentimentResponse)
async def analyze_sentiment(text: str):
    # Wywołaj usługę LLM
    async with httpx.AsyncClient() as client:
        response = await client.post(
            "http://localhost:11434/api/generate",
            json={
                "model": "qwen2.5",
                "prompt": f"Analiza sentymentu: {text}",
                "format": SentimentResponse.schema_json()
            }
        )
    return response.json()

Najlepsze praktyki i wskazówki

1. Zastosuj konsekwentnie dekoratory operacji ścieżki

Zorganizuj swoje punkty końcowe z wyraźnymi metodami HTTP:

@app.get("/items/")      # Lista elementów
@app.post("/items/")     # Utwórz element
@app.get("/items/{id}")  # Pobierz konkretny element
@app.put("/items/{id}")  # Zaktualizuj element
@app.delete("/items/{id}") # Usuń element

2. Wersjonuj swój API

Zawieraj wersjonowanie API od samego początku:

from fastapi import APIRouter

api_v1 = APIRouter(prefix="/api/v1")
api_v2 = APIRouter(prefix="/api/v2")

@api_v1.get("/users/")
async def get_users_v1():
    return {"version": "1.0"}

app.include_router(api_v1)
app.include_router(api_v2)

3. Używaj zmiennych środowiskowych

Nigdy nie koduj wrażliwych danych. Używaj zmiennych środowiskowych:

from pydantic import BaseSettings

class Settings(BaseSettings):
    database_url: str
    secret_key: str
    api_key: str
    
    class Config:
        env_file = ".env"

settings = Settings()

4. Zaimplementuj odpowiednie logowanie

Użyj modułu logowania Pythona:

import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@app.get("/items/")
async def get_items():
    logger.info("Pobieranie wszystkich elementów")
    return items

5. Monitoruj wydajność

Użyj middleware do pomiaru czasu żądania:

import time
from fastapi import Request

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response

FastAPI vs. Inne frameworki

FastAPI vs. Flask

Flask jest bardziej minimalistyczny i daje Ci więcej kontroli, ale FastAPI oferuje więcej funkcji domyślnie:

  • FastAPI ma automatyczną walidację i dokumentację
  • Flask wymaga rozszerzeń do obsługi asynchronicznej
  • FastAPI jest znacznie szybszy w operacjach I/O
  • Flask ma większą ekosystemę i więcej zasobów edukacyjnych

FastAPI vs. Django REST Framework

Django REST Framework (DRF) jest częścią większego ekosystemu Django:

  • DRF zawiera pełny ORM i interfejs administratora
  • FastAPI jest lżejszy i szybszy
  • DRF jest lepszy dla złożonych aplikacji opartych na bazie danych
  • FastAPI wyróżnia się w mikrousługach i samodzielnych interfejsach API

FastAPI vs. Node.js/Express

FastAPI oferuje prostotę Pythona z wydajnością porównywalną do Node.js:

  • Podobne właściwości asynchroniczne
  • System typów Pythona jest bardziej solidny niż JavaScript/TypeScript
  • Node.js ma większą ekosystemę pakietów
  • Dokumentacja automatyczna FastAPI jest lepsza

Przypadki użycia w praktyce

Architektura mikrousług

Lekkości FastAPI i szybkiego czasu uruchamiania czynią go idealnym dla mikrousług. Każda usługa może być niezależnie wdrażana i skalowana.

API do uczenia maszynowego

Służyć modelom uczenia maszynowego to typowe zastosowanie FastAPI. Frameworka obsługa asynchroniczna efektywnie obsługuje wiele żądań prognozy.

Backend dla aplikacji mobilnych/webowych

FastAPI jest doskonałym backendem dla nowoczesnych aplikacji SPA (Single Page Applications) i aplikacji mobilnych dzięki automatycznemu obsłudze CORS i wsparciu WebSockets.

Zebranie danych z IoT

FastAPI może obsługiwać dużą ilość danych z urządzeń IoT, efektywnie przetwarzając i przechowując dane z czujników.

Chatboty i interfejsy konwersacyjne AI

Tworzenie interfejsów konwersacyjnych i backendów chatbotów korzysta z wsparcia WebSockets i możliwości asynchronicznych FastAPI.

Typowe pułapki i rozwiązania

1. Operacje blokujące w funkcjach asynchronicznych

Problem: Uruchamianie kodu synchronicznego, blokującego w funkcjach asynchronicznych:

@app.get("/slow")
async def slow_endpoint():
    time.sleep(10)  # Blokuje cały pętlę zdarzeń!
    return {"status": "zakończone"}

Rozwiązanie: Użyj run_in_executor dla operacji blokujących:

from fastapi import BackgroundTasks
import asyncio

@app.get("/fast")
async def fast_endpoint():
    loop = asyncio.get_event_loop()
    result = await loop.run_in_executor(None, blocking_function)
    return {"result": result}

2. Nie korzystanie z modeli odpowiedzi

Problem: Zwracanie surowych obiektów bazy danych ujawnia wewnętrzną strukturę.

Rozwiązanie: Zawsze definiuj modele odpowiedzi:

@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
    return db_user  # Automatycznie filtrowany przez UserResponse

3. Niewystarczająca obsługa błędów

Problem: Nieobsłużone wyjątki powodują awarię aplikacji.

Rozwiązanie: Użyj obsługiwanych wyjątków:

@app.exception_handler(ValueError)
async def value_error_handler(request, exc):
    return JSONResponse(
        status_code=400,
        content={"message": str(exc)}
    )

Zasoby ekosystemu Pythona

FastAPI działa płynnie z większym ekosystemem Pythona. Aby uzyskać kompleksowy przegląd podstaw Pythona, sprawdź Python Cheatsheet, który pokrywa istotne składniki Pythona i wzorce, które używasz w aplikacjach FastAPI.

Podsumowanie

FastAPI reprezentuje znaczący postęp w projektowaniu frameworków webowych w Pythonie. Przyjmując nowoczesne funkcje Pythona, takie jak wskazówki typów i async/await, dostarcza wyjątkowej wydajności i doświadczenia dewelopera. Niezależnie od tego, czy tworzysz prosty interfejs REST API, czy złożoną architekturę mikrousług, FastAPI dostarcza narzędzi i wydajności potrzebnych do aplikacji produkcyjnych.

Automatyczna dokumentacja, bezpieczeństwo typów i intuicyjny projekt czynią z niego doskonały wybór zarówno dla początkujących, jak i doświadczonych deweloperów. Z miarą rozwoju ekosystemu Pythona, FastAPI pozycjonuje się jako framework dla nowoczesnego tworzenia interfejsów API.

Zacznij od prostego API, eksploruj dokumentację i stopniowo przyjmuj bardziej zaawansowane funkcje w miarę rozwoju aplikacji. Społeczność FastAPI jest aktywna i pomocna, oferując rozszerzonych dokumentacji i przykładów, które Cię wskazują.

Przydatne linki

Zewnętrzne zasoby i odniesienia