FastAPI – wprowadzenie i podstawy

Kacper Sieradziński
Kacper Sieradziński
14 maja 2025Edukacja4 min czytania

FastAPI to nowoczesny framework webowy w Pythonie, zaprojektowany z myślą o tworzeniu szybkich i nowoczesnych REST API. Został zbudowany na standardzie ASGI (Asynchronous Server Gateway Interface), co pozwala na natywną obsługę asynchroniczności (async/await).

Obraz główny FastAPI – wprowadzenie i podstawy

Łączy w sobie wydajność, prostotę i bezpieczeństwo typów, dzięki czemu tworzenie API jest szybkie, przyjemne i przewidywalne. W tym przewodniku poznasz podstawy FastAPI: instalację, routing, walidację danych, asynchroniczne endpointy i automatyczną dokumentację.

Dlaczego FastAPI?

FastAPI łączy to, co najlepsze z innych frameworków:

  • prostotę Flaska,
  • typowanie znane z TypeScript,
  • szybkość porównywalną z Node.js i Go,
  • oraz automatyczną dokumentację OpenAPI.

Najważniejsze zalety

  • Asynchroniczność i wysoka wydajność (ASGI) — obsługa tysięcy równoczesnych połączeń
  • Walidacja danych dzięki Pydantic — automatyczna walidacja bez boilerplate'u
  • Automatyczna dokumentacja Swagger i ReDoc — "z pudełka", bez dodatkowej konfiguracji
  • Wbudowane wsparcie dla autoryzacji i OAuth2 — gotowe klasy do implementacji
  • Łatwe testowanie i dependency injection — czysty, modułowy kod

FastAPI został stworzony przez Sebastiána Ramíreza w 2018 roku i szybko zdobył popularność w społeczności Pythona, stając się jednym z najszybciej rozwijających się frameworków.

Instalacja FastAPI i Uvicorn

Zacznij od instalacji frameworka oraz serwera ASGI:

Bash
1 pip install fastapi uvicorn[standard]

Opcjonalnie możesz zainstalować dodatkowe zależności:

Bash
1 pip install fastapi uvicorn[standard] python-multipart

Utwórz plik main.py

Python
1 2 3 4 5 6 7 8 9 10 11 from fastapi import FastAPI app = FastAPI(title="My FastAPI App", version="1.0.0") @app.get("/") def read_root(): return {"message": "Witaj w FastAPI!"} @app.get("/health") def health_check(): return {"status": "ok", "version": "1.0.0"}

Uruchom serwer

Bash
1 uvicorn main:app --reload

Parametr --reload automatycznie przeładowuje aplikację przy zmianach w kodzie (tylko dla developmentu).

Aplikacja będzie dostępna pod adresem:

Bash
1 http://127.0.0.1:8000

Dokumentacja interaktywna (Swagger UI):

Bash
1 http://127.0.0.1:8000/docs

Alternatywna dokumentacja (ReDoc):

Bash
1 http://127.0.0.1:8000/redoc

Konfiguracja serwera

Bash
1 2 3 4 5 6 7 8 9 10 11 12 13 14 # Podstawowe uruchomienie uvicorn main:app # Z automatycznym przeładowaniem (development) uvicorn main:app --reload # Na określonym hoście i porcie uvicorn main:app --host 0.0.0.0 --port 8080 # Z większą liczbą workerów (produkcja) uvicorn main:app --workers 4 # Z określonym logowaniem uvicorn main:app --log-level info

Routing – tworzenie endpointów

FastAPI udostępnia dekoratory odpowiadające metodom HTTP (@app.get(), @app.post(), @app.put(), @app.delete(), @app.patch()).

Podstawowe endpointy

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from fastapi import FastAPI app = FastAPI() @app.get("/users") def list_users(): return [ {"id": 1, "name": "Kacper"}, {"id": 2, "name": "Anna"} ] @app.get("/users/{user_id}") def get_user(user_id: int): return {"id": user_id, "name": f"Użytkownik {user_id}"} @app.post("/users") def create_user(): return {"status": "created"} @app.put("/users/{user_id}") def update_user(user_id: int): return {"id": user_id, "status": "updated"} @app.delete("/users/{user_id}") def delete_user(user_id: int): return {"id": user_id, "status": "deleted"}

Wszystkie ścieżki są automatycznie dokumentowane i widoczne w interaktywnym interfejsie /docs. FastAPI automatycznie wykrywa typy parametrów i waliduje je.

Typy parametrów ścieżek

Python
1 2 3 4 5 6 7 @app.get("/users/{user_id}") def get_user(user_id: int): # Automatyczna konwersja i walidacja return {"user_id": user_id} @app.get("/files/{file_path:path}") def read_file(file_path: str): # :path pozwala na slashe w ścieżce return {"file_path": file_path}

Kody statusu HTTP

Python
1 2 3 4 5 6 7 8 9 from fastapi import FastAPI, status @app.post("/users", status_code=status.HTTP_201_CREATED) def create_user(): return {"status": "created"} @app.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_user(user_id: int): return None

Parametry zapytań i ścieżek

FastAPI automatycznie odczytuje parametry z adresu i zapytań.

Parametry query

Python
1 2 3 4 5 6 7 8 9 10 from typing import Optional @app.get("/search") def search_users(query: str = "", limit: int = 10, skip: int = 0): return { "query": query, "limit": limit, "skip": skip, "results": [] }

Wywołanie:

Bash
1 /search?query=python&limit=5&skip=0

Wynik:

JSON
1 2 3 4 5 6 { "query": "python", "limit": 5, "skip": 0, "results": [] }

Parametry z walidacją

Python
1 2 3 4 5 6 7 8 9 from fastapi import Query @app.get("/items") def list_items( q: Optional[str] = Query(None, min_length=3, max_length=50), limit: int = Query(10, ge=1, le=100), # ge = greater or equal, le = less or equal skip: int = Query(0, ge=0) ): return {"q": q, "limit": limit, "skip": skip}

Parametry ścieżki z walidacją

Python
1 2 3 4 5 6 7 from fastapi import Path @app.get("/users/{user_id}") def get_user( user_id: int = Path(..., gt=0, description="ID użytkownika") ): return {"user_id": user_id}

Opcjonalne parametry

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 from typing import Optional @app.get("/users/{user_id}/posts") def get_user_posts( user_id: int, published: Optional[bool] = None, limit: int = 10 ): return { "user_id": user_id, "published": published, "limit": limit }

Walidacja danych z Pydantic

FastAPI integruje się z biblioteką Pydantic, co pozwala automatycznie walidować dane wejściowe i wyjściowe.

Przykład modelu użytkownika

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pydantic import BaseModel, EmailStr, Field from typing import Optional class User(BaseModel): id: int = Field(..., gt=0, description="ID użytkownika") name: str = Field(..., min_length=3, max_length=100) email: EmailStr age: Optional[int] = Field(None, ge=0, le=120) class Config: schema_extra = { "example": { "id": 1, "name": "Kacper Sieradziński", "email": "kacper@example.com", "age": 25 } }

Użycie modelu w endpointach

Python
1 2 3 4 5 6 7 8 9 10 11 @app.post("/users") def create_user(user: User): return {"status": "created", "user": user} @app.get("/users/{user_id}", response_model=User) def get_user(user_id: int): return User( id=user_id, name="Kacper", email="kacper@example.com" )

Jeśli klient wyśle błędne dane (np. email jako liczbę), FastAPI automatycznie zwróci błąd:

JSON
1 2 3 4 5 6 7 8 9 { "detail": [ { "loc": ["body", "email"], "msg": "value is not a valid email address", "type": "value_error.email" } ] }

Bez ręcznego pisania walidatorów — wszystko działa automatycznie.

Zaawansowana walidacja

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pydantic import BaseModel, validator, EmailStr class UserCreate(BaseModel): name: str email: EmailStr password: str @validator('name') def name_must_not_be_empty(cls, v): if not v.strip(): raise ValueError('Name cannot be empty') return v.strip() @validator('password') def password_must_be_strong(cls, v): if len(v) < 8: raise ValueError('Password must be at least 8 characters') return v

Asynchroniczne endpointy

Dzięki ASGI FastAPI obsługuje asynchroniczne funkcje natywnie.

Podstawowy przykład

Python
1 2 3 4 5 6 import asyncio @app.get("/slow") async def slow_endpoint(): await asyncio.sleep(2) return {"message": "Gotowe po 2 sekundach"}

Asynchroniczność oznacza, że aplikacja może obsługiwać wiele żądań jednocześnie bez blokowania głównego wątku — idealne do zapytań do API, baz danych i operacji sieciowych.

Asynchroniczne operacje I/O

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import httpx @app.get("/external-data") async def get_external_data(): async with httpx.AsyncClient() as client: response = await client.get("https://api.example.com/data") return response.json() @app.get("/multiple-requests") async def get_multiple_data(): async with httpx.AsyncClient() as client: # Równoległe wykonywanie wielu żądań task1 = client.get("https://api1.example.com/data") task2 = client.get("https://api2.example.com/data") task3 = client.get("https://api3.example.com/data") responses = await asyncio.gather(task1, task2, task3) return [r.json() for r in responses]

Kiedy używać async?

Używaj async dla:

  • Operacji I/O (zapytania HTTP, baza danych, pliki)
  • Długotrwałych operacji sieciowych
  • Wiele równoczesnych żądań

Nie używaj async dla:

  • Operacji CPU-bound (obliczenia matematyczne)
  • Prostej logiki biznesowej

Struktura projektu

Dla większych aplikacji zaleca się modularny układ:

Bash
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 app/ ├── main.py # Główny plik aplikacji ├── routers/ # Endpointy (API layer) │ ├── __init__.py │ ├── users.py │ └── auth.py ├── models/ # Modele bazy danych (SQLAlchemy) │ ├── __init__.py │ └── user.py ├── schemas/ # Modele Pydantic │ ├── __init__.py │ └── user.py ├── services/ # Logika biznesowa │ ├── __init__.py │ └── user_service.py ├── database.py # Konfiguracja bazy danych └── requirements.txt

Przykład modularnego routingu

routers/users.py:

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from fastapi import APIRouter, HTTPException from pydantic import BaseModel from typing import List router = APIRouter(prefix="/users", tags=["users"]) class User(BaseModel): id: int name: str email: str @router.get("/", response_model=List[User]) def list_users(): return [ User(id=1, name="Kacper", email="kacper@example.com"), User(id=2, name="Anna", email="anna@example.com") ] @router.get("/{user_id}", response_model=User) def get_user(user_id: int): if user_id == 1: return User(id=1, name="Kacper", email="kacper@example.com") raise HTTPException(status_code=404, detail="User not found")

main.py:

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from fastapi import FastAPI from app.routers import users, auth app = FastAPI( title="My API", version="1.0.0", description="API do zarządzania użytkownikami" ) app.include_router(users.router) app.include_router(auth.router) @app.get("/") def root(): return {"message": "Welcome to My API"}

Dzięki tags=["users"] wszystkie endpointy z tego routera będą zgrupowane w dokumentacji Swagger.

Globalne prefixy i konfiguracja

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 from fastapi import APIRouter # Router z prefixem i tagami api_router = APIRouter(prefix="/api/v1") users_router = APIRouter( prefix="/users", tags=["Users"], responses={404: {"description": "Not found"}} ) api_router.include_router(users_router) app.include_router(api_router)

Dokumentacja OpenAPI i Swagger

FastAPI automatycznie generuje dokumentację API w dwóch formatach:

  • /docs – interaktywna dokumentacja Swagger UI (można testować endpointy)
  • /redoc – czytelna dokumentacja w stylu ReDoc

Konfiguracja dokumentacji

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from fastapi import FastAPI app = FastAPI( title="My API", version="1.0.0", description="API do zarządzania użytkownikami", terms_of_service="http://example.com/terms/", contact={ "name": "Kacper Sieradziński", "email": "kacper@example.com", }, license_info={ "name": "MIT", "url": "https://opensource.org/licenses/MIT", }, )

Dodawanie opisów do endpointów

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @app.post( "/users", status_code=201, summary="Utwórz użytkownika", description="Utworzy nowego użytkownika w systemie. Wymaga unikalnego emaila.", response_description="Utworzony użytkownik", tags=["Users"] ) def create_user(user: UserCreate): """Utwórz nowego użytkownika. - **name**: Imię użytkownika (min. 3 znaki) - **email**: Adres e-mail użytkownika (walidacja formatu) """ return create_user_in_db(user)

Każdy endpoint zdefiniowany w kodzie pojawi się w dokumentacji, wraz z modelami danych, walidacją i opisami. FastAPI automatycznie generuje schemat OpenAPI na podstawie typów i adnotacji.

Testowanie w FastAPI

FastAPI ma wbudowane narzędzia do testowania przy użyciu pytest i TestClient.

Instalacja pytest

Bash
1 pip install pytest httpx

Przykład testu

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from fastapi.testclient import TestClient from main import app client = TestClient(app) def test_read_root(): response = client.get("/") assert response.status_code == 200 assert response.json() == {"message": "Witaj w FastAPI!"} def test_create_user(): response = client.post( "/users", json={"id": 1, "name": "Kacper", "email": "kacper@example.com"} ) assert response.status_code == 200 data = response.json() assert data["name"] == "Kacper" def test_get_user_not_found(): response = client.get("/users/999") assert response.status_code == 404

Uruchom testy:

Bash
1 pytest -v

Asynchroniczne testy

Python
1 2 3 4 5 6 7 8 9 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("/slow") assert response.status_code == 200 assert response.json()["message"] == "Gotowe po 2 sekundach"

Autoryzacja i bezpieczeństwo

FastAPI zawiera gotowe klasy dla OAuth2, JWT i API Key, które możesz łatwo zaimplementować w systemie autoryzacji. Dzięki dependency injection możesz bezpiecznie kontrolować dostęp do endpointów.

Podstawowy przykład OAuth2

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @app.get("/protected") async def protected(token: str = Depends(oauth2_scheme)): if token != "secret": raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token" ) return {"message": "Authorized!"}

API Key authentication

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from fastapi import Depends, HTTPException, status from fastapi.security import APIKeyHeader api_key_header = APIKeyHeader(name="X-API-Key") def verify_api_key(api_key: str = Depends(api_key_header)): if api_key != "secret-api-key": raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Invalid API Key" ) return api_key @app.get("/secure") async def secure_endpoint(api_key: str = Depends(verify_api_key)): return {"message": "This is a secure endpoint"}

Wywołanie:

HTTP
1 2 GET /secure HTTP/1.1 X-API-Key: secret-api-key

CORS (Cross-Origin Resource Sharing)

Python
1 2 3 4 5 6 7 8 9 from fastapi.middleware.cors import CORSMiddleware app.add_middleware( CORSMiddleware, allow_origins=["https://example.com", "http://localhost:3000"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )

Zaawansowane funkcje

Response models

Możesz definiować modele odpowiedzi oddzielnie od modeli wejściowych:

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from pydantic import BaseModel from datetime import datetime class UserCreate(BaseModel): name: str email: str class UserResponse(BaseModel): id: int name: str email: str created_at: datetime @app.post("/users", response_model=UserResponse) def create_user(user: UserCreate): # FastAPI automatycznie zwróci tylko pola z UserResponse return UserResponse(id=1, **user.dict(), created_at=datetime.now())

Background tasks

Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from fastapi import BackgroundTasks def send_email(email: str, message: str): # Wyślij e-mail w tle print(f"Sending email to {email}: {message}") @app.post("/users") def create_user(user: UserCreate, background_tasks: BackgroundTasks): # Utwórz użytkownika new_user = create_user_in_db(user) # Dodaj zadanie w tle background_tasks.add_task(send_email, user.email, "Welcome!") return new_user

WebSockets

Python
1 2 3 4 5 6 7 8 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"Echo: {data}")

Podsumowanie

FastAPI to framework, który pozwala budować wydajne aplikacje dzięki asynchroniczności, bezpieczne API dzięki Pydantic i OAuth2, czytelny kod dzięki typowaniu oraz kompletną dokumentację automatycznie generowaną przez OpenAPI.

Najważniejsze cechy FastAPI:

  • Szybkość — porównywalna z Node.js i Go
  • Prostota — łatwa nauka i czytelny kod
  • Typowanie — autouzupełnianie w IDE i wykrywanie błędów
  • Automatyczna walidacja — dzięki Pydantic
  • Automatyczna dokumentacja — Swagger i ReDoc "z pudełka"
  • Asynchroniczność — natywne wsparcie dla async/await
  • Bezpieczeństwo — wbudowane wsparcie dla OAuth2 i JWT

Jeśli chcesz tworzyć nowoczesne REST API w Pythonie, FastAPI to najlepszy punkt wyjścia. Zacznij od prostych endpointów, stopniowo dodawaj walidację, autoryzację i zaawansowane funkcjonalności — wszystko przy zachowaniu czytelności i wydajności kodu.

Tagi

#Python#FastAPI#REST API#ASGI