Skip to content
Back to Stack Recommender

Python FastAPI for APIs

Async Python APIs with FastAPI, Pydantic v2 validation, SQLAlchemy 2, and auto OpenAPI docs.

API ServicesModerate

Stack Components

FrameworkFastAPI 0.115
ValidationPydantic v2
ORMSQLAlchemy 2 (async)
DBPostgreSQL + asyncpg
Authfastapi-users + JWT
DeployUvicorn + Gunicorn + Docker

Why

FastAPI is ASGI async (10x Flask throughput), Pydantic v2 is Rust-core (50x faster validation), and OpenAPI docs auto-generate from type hints. Python 3.12 + async makes it viable for high-concurrency APIs previously needing Go/Node.

When

Choose FastAPI for ML/AI APIs (Python ecosystem), data-heavy backends, and teams with Python skills. Avoid for CPU-bound work (use Go/Rust) or if you need GraphQL (Strawberry adds complexity).

How

1. Scaffold — pip install fastapi uvicorn[standard], or "fastapi new" with fastapi-cli 2. Pydantic models — class User(BaseModel) with typed fields, auto-validated 3. Routes — @app.post("/users"), type hints = validation + docs + serialization 4. Async DB — SQLAlchemy 2 async session, asyncpg driver, dependency injection 5. Dependencies — Depends(get_db), Depends(get_current_user), reusable & testable 6. Auth — fastapi-users with JWT, OAuth2PasswordBearer, auto /docs login 7. Testing — pytest + httpx.AsyncClient, TestClient for sync, fixtures for DB 8. Deploy — gunicorn -k uvicorn.workers.UvicornWorker -w 4, behind nginx, in Docker

Example

# models.py — Pydantic v2 (Rust-core validation) from pydantic import BaseModel, EmailStr, Field from datetime import datetime from uuid import UUID class UserCreate(BaseModel): email: EmailStr name: str = Field(min_length=1, max_length=100) class UserResponse(BaseModel): id: UUID email: EmailStr name: str created_at: datetime # main.py — async routes with dependency injection from fastapi import FastAPI, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession app = FastAPI(title="User API", version="1.0") async def get_db() -> AsyncSession: async with async_session() as session: yield session @app.post("/users", response_model=UserResponse, status_code=201) async def create_user( user: UserCreate, # auto-validated by Pydantic db: AsyncSession = Depends(get_db), # DI: async DB session ): # Check duplicate existing = await db.execute(select(User).where(User.email == user.email)) if existing.scalar_one_or_none(): raise HTTPException(409, "Email already registered") new_user = User(**user.model_dump()) db.add(new_user) await db.commit() await db.refresh(new_user) return new_user # auto-serialized to UserResponse # Run: uvicorn main:app --reload # Docs auto at /docs (Swagger) and /redoc (ReDoc)

Common Problems

  • ⚠Sync code in async route — blocks event loop, use asyncpg not psycopg2, run_in_executor for sync
  • ⚠N+1 queries — lazy-loading relationships in loop, use selectinload() or joinedload()
  • ⚠Pydantic v1 vs v2 migration — .dict() → .model_dump(), Config → model_config
  • ⚠Missing await — async function returns coroutine not result, silent bug

Best Practices

  • ✓Use async everywhere — asyncpg, async session, async httpx — never block event loop
  • ✓Pydantic for all I/O — request body, response model, query params, all validated
  • ✓Dependency injection for cross-cutting — DB, auth, rate limit as Depends, testable
  • ✓Background tasks for side effects — email, webhooks via BackgroundTasks, don't block response

FAQ

What is Python FastAPI for APIs and what projects is it for?

Async Python APIs with FastAPI, Pydantic v2 validation, SQLAlchemy 2, and auto OpenAPI docs. It pairs layered technologies for end-to-end type safety and out-of-the-box deploys, fitting everything from MVPs to production SaaS.

How do I spin up a working demo with Python FastAPI for APIs in 10 minutes?

Two steps: (1) Scaffold — pip install fastapi uvicorn[standard], or "fastapi new" with fastapi-cli; (2) Pydantic models — class User(BaseModel) with typed fields, auto-validated. Get the local dev server running, then wire one real data source to verify the end-to-end loop.

What is the most common pitfall with Python FastAPI for APIs and how do I avoid it?

The most common pitfall is: Sync code in async route — blocks event loop, use asyncpg not psycopg2, run_in_executor for sync. Avoid it by adding the matching checklist to your PR template and running type-check + lint + unit tests in CI — three gates before merge.

What are the best practices for Python FastAPI for APIs?

Best practices for Python FastAPI for APIs include: Use async everywhere — asyncpg, async session, async httpx — never block event loop; Pydantic for all I/O — request body, response model, query params, all validated; Dependency injection for cross-cutting — DB, auth, rate limit as Depends, testable. The first one — "Use async everywhere — asyncpg, async session, async httpx — never block event loop" — should be set up at project init to avoid costly rework later.

When should I NOT choose Python FastAPI for APIs?

Pick something else in three cases: (1) the team has zero experience with the core framework and the deadline is tight (learning-curve risk); (2) it's a pure content/marketing site (Astro is lighter); (3) you need very high throughput (>10k RPS) or strict-consistency microservices (Go/Rust). Python FastAPI for APIs shines for mid-to-high complexity full-stack and API work — don't over-engineer simple static pages with it.