FastAPI Complete Guide: Build High-Performance Python APIs in 2026

February 12, 202625 min read

FastAPI is the fastest-growing Python web framework. It combines the simplicity of Flask with the performance of Node.js, adds automatic data validation through Pydantic, and generates interactive API documentation out of the box. Built on top of Starlette for the web layer and Pydantic for the data layer, FastAPI lets you write production-grade APIs with Python type hints — and it catches bugs before they reach production.

This guide takes you from your first endpoint through production deployment, with working code at every step. You will learn path operations, Pydantic models, dependency injection, JWT authentication, database integration, background tasks, testing, and performance tuning.

⚙ Related resources: Test your API endpoints with the API Request Builder, mock responses with the API Mock Builder, and learn REST conventions in our REST API Design Guide. For escalation ownership when incident ACK deadlines are missed, use Merge Queue ACK Timeout Remediation Runbook.

1. What Is FastAPI?

FastAPI is a modern, high-performance web framework for building APIs with Python 3.7+ based on standard Python type hints. Created by Sebastian Ramirez and first released in 2018, it has become one of the most starred Python web frameworks on GitHub.

Key features that set FastAPI apart:

Feature FastAPI Flask Django REST
Async supportNativeLimitedPartial
Auto docsBuilt-inExtensionsBuilt-in
ValidationPydantic (auto)ManualSerializers
Type hintsCore featureOptionalOptional
PerformanceVery highModerateModerate
Dependency injectionBuilt-inNoNo

2. Installation & Setup

Install FastAPI and Uvicorn (the ASGI server) in a virtual environment:

# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate  # Linux/macOS
# venv\Scripts\activate   # Windows

# Install FastAPI with all optional dependencies
pip install "fastapi[standard]"

# Or install just the essentials
pip install fastapi uvicorn[standard]

A clean project structure for a FastAPI application:

my-api/
  app/
    __init__.py
    main.py          # FastAPI app instance and startup
    config.py         # Settings via pydantic-settings
    models.py         # SQLAlchemy models
    schemas.py        # Pydantic request/response schemas
    database.py       # DB engine and session
    dependencies.py   # Shared dependencies (auth, DB session)
    routers/
      __init__.py
      users.py        # /users endpoints
      items.py        # /items endpoints
  tests/
    test_users.py
    test_items.py
  requirements.txt
  Dockerfile

Create your first app in app/main.py:

from fastapi import FastAPI

# Create the FastAPI application instance
app = FastAPI(
    title="My API",
    description="A production-ready FastAPI application",
    version="1.0.0",
)

@app.get("/")
async def root():
    return {"message": "Hello, FastAPI!"}

Run the development server:

# Start with auto-reload for development
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000

# Visit http://localhost:8000/docs for interactive Swagger UI
# Visit http://localhost:8000/redoc for ReDoc documentation

3. Path Operations

FastAPI uses decorators for each HTTP method. Path parameters are extracted from the URL, and query parameters are taken from function arguments that are not part of the path:

from fastapi import FastAPI, Query, Path

app = FastAPI()

# GET with path parameters
@app.get("/users/{user_id}")
async def get_user(
    user_id: int = Path(..., title="User ID", ge=1)
):
    return {"user_id": user_id}

# GET with query parameters
@app.get("/items/")
async def list_items(
    skip: int = Query(0, ge=0, description="Items to skip"),
    limit: int = Query(20, ge=1, le=100, description="Max items"),
    search: str | None = Query(None, min_length=1, max_length=100),
):
    # skip, limit, and search come from ?skip=0&limit=20&search=foo
    return {"skip": skip, "limit": limit, "search": search}

# POST to create a resource
@app.post("/users/", status_code=201)
async def create_user(name: str, email: str):
    return {"name": name, "email": email}

# PUT to update a resource
@app.put("/users/{user_id}")
async def update_user(user_id: int, name: str):
    return {"user_id": user_id, "name": name}

# DELETE a resource
@app.delete("/users/{user_id}", status_code=204)
async def delete_user(user_id: int):
    return None

The Path() and Query() functions add validation, metadata, and documentation. The first argument (...) means the parameter is required. Use a default value to make it optional.

4. Request Body & Pydantic Models

Pydantic models are the backbone of FastAPI's data validation. Define a model with type hints and FastAPI automatically validates incoming JSON, returns clear error messages, and generates schema documentation:

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

# Request model for creating a user
class UserCreate(BaseModel):
    name: str = Field(
        ..., min_length=1, max_length=100,
        examples=["Alice Johnson"]
    )
    email: EmailStr  # Validates email format automatically
    age: int = Field(..., ge=13, le=150, description="User age")
    bio: str | None = Field(None, max_length=500)

# Nested models for complex data
class Address(BaseModel):
    street: str
    city: str
    country: str = "US"
    zip_code: str = Field(..., pattern=r"^\d{5}(-\d{4})?$")

class UserWithAddress(BaseModel):
    name: str
    email: EmailStr
    addresses: list[Address] = []  # List of nested objects

# Use the model in an endpoint
@app.post("/users/", status_code=201)
async def create_user(user: UserCreate):
    # user is already validated - if invalid, FastAPI returns 422
    return {"id": 1, **user.model_dump()}

When a client sends invalid data, FastAPI automatically returns a 422 response with details about every validation error:

{
  "detail": [
    {
      "type": "value_error",
      "loc": ["body", "email"],
      "msg": "value is not a valid email address",
      "input": "not-an-email"
    }
  ]
}

Custom validators let you add business logic to your models:

from pydantic import BaseModel, field_validator, model_validator

class OrderCreate(BaseModel):
    product_id: int
    quantity: int = Field(..., ge=1, le=1000)
    discount_code: str | None = None

    @field_validator("discount_code")
    @classmethod
    def validate_discount(cls, v):
        if v and not v.startswith("PROMO-"):
            raise ValueError("Discount codes must start with PROMO-")
        return v.upper() if v else v

    @model_validator(mode="after")
    def check_order(self):
        if self.quantity > 100 and not self.discount_code:
            raise ValueError("Bulk orders over 100 need a discount code")
        return self

5. Response Models

Use response_model to control what data is sent back to the client. This filters out internal fields like passwords and adds documentation to the OpenAPI schema:

from pydantic import BaseModel, EmailStr

class UserCreate(BaseModel):
    name: str
    email: EmailStr
    password: str  # Sent by client, but never returned

class UserResponse(BaseModel):
    id: int
    name: str
    email: EmailStr
    is_active: bool = True

    model_config = {"from_attributes": True}  # Read from ORM objects

# response_model filters out the password field
@app.post("/users/", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
    # Even if the db_user object has a password field,
    # response_model ensures it is never sent to the client
    db_user = save_to_db(user)
    return db_user

# Return a list of items
@app.get("/users/", response_model=list[UserResponse])
async def list_users():
    return get_all_users()

# Custom responses for different status codes
from fastapi.responses import JSONResponse

@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
    user = find_user(user_id)
    if not user:
        return JSONResponse(
            status_code=404,
            content={"detail": "User not found"}
        )
    return user

6. Dependency Injection

FastAPI's dependency injection system is one of its most powerful features. Use Depends() to inject shared logic — database sessions, authentication, pagination, rate limiting — into any endpoint:

from fastapi import Depends, FastAPI, HTTPException
from sqlalchemy.orm import Session

app = FastAPI()

# Database session dependency
def get_db():
    db = SessionLocal()
    try:
        yield db  # yield makes this a generator dependency
    finally:
        db.close()  # Always close, even on errors

# Pagination dependency (reusable across endpoints)
class Pagination:
    def __init__(
        self,
        skip: int = Query(0, ge=0),
        limit: int = Query(20, ge=1, le=100),
    ):
        self.skip = skip
        self.limit = limit

# Use dependencies in endpoints
@app.get("/users/")
async def list_users(
    db: Session = Depends(get_db),
    pagination: Pagination = Depends(),
):
    users = db.query(User).offset(pagination.skip).limit(pagination.limit).all()
    return users

# Sub-dependencies: dependencies can depend on other dependencies
def get_current_user(
    token: str = Depends(oauth2_scheme),
    db: Session = Depends(get_db),
):
    user = decode_token_and_find_user(token, db)
    if not user:
        raise HTTPException(status_code=401, detail="Invalid token")
    return user

def get_admin_user(
    current_user: User = Depends(get_current_user),
):
    if not current_user.is_admin:
        raise HTTPException(status_code=403, detail="Admin required")
    return current_user

@app.delete("/users/{user_id}")
async def delete_user(
    user_id: int,
    admin: User = Depends(get_admin_user),  # Chain of deps
    db: Session = Depends(get_db),
):
    # Only admins reach this code
    db.query(User).filter(User.id == user_id).delete()
    db.commit()

7. Authentication with JWT

FastAPI provides built-in OAuth2 support. Here is a complete JWT authentication flow with password hashing:

from datetime import datetime, timedelta
from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel

# Configuration
SECRET_KEY = "your-secret-key-from-env"  # Use os.environ in production
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# Password hashing with bcrypt
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# OAuth2 token URL (also creates the login button in Swagger UI)
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

app = FastAPI()

class Token(BaseModel):
    access_token: str
    token_type: str

class TokenData(BaseModel):
    username: str | None = None

# Hash and verify passwords
def verify_password(plain: str, hashed: str) -> bool:
    return pwd_context.verify(plain, hashed)

def get_password_hash(password: str) -> str:
    return pwd_context.hash(password)

# Create JWT tokens
def create_access_token(data: dict, expires_delta: timedelta | None = None):
    to_encode = data.copy()
    expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15))
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

# Dependency to get current user from token
async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    user = get_user_from_db(username)
    if user is None:
        raise credentials_exception
    return user

# Login endpoint
@app.post("/token", response_model=Token)
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=401,
            detail="Incorrect username or password",
        )
    access_token = create_access_token(
        data={"sub": user.username},
        expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES),
    )
    return {"access_token": access_token, "token_type": "bearer"}

# Protected endpoint
@app.get("/users/me")
async def read_users_me(current_user = Depends(get_current_user)):
    return current_user
⚙ Test your auth flow: Use the API Request Builder to send token requests and test protected endpoints. Format JWT payloads with the JSON Formatter.

8. Database Integration

FastAPI works with any database. The most common setup is SQLAlchemy with a session dependency. Here is the full pattern:

# app/database.py
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, DeclarativeBase

SQLALCHEMY_DATABASE_URL = "postgresql://user:pass@localhost/mydb"

engine = create_engine(SQLALCHEMY_DATABASE_URL, pool_pre_ping=True)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

class Base(DeclarativeBase):
    pass
# app/models.py
from sqlalchemy import Column, Integer, String, Boolean, DateTime, ForeignKey
from sqlalchemy.orm import relationship
from datetime import datetime
from .database import Base

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    email = Column(String, unique=True, index=True, nullable=False)
    name = Column(String(100), nullable=False)
    hashed_password = Column(String, nullable=False)
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, default=datetime.utcnow)

    # Relationship: one user has many items
    items = relationship("Item", back_populates="owner")

class Item(Base):
    __tablename__ = "items"

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String(200), nullable=False)
    description = Column(String)
    owner_id = Column(Integer, ForeignKey("users.id"))

    owner = relationship("User", back_populates="items")
# app/routers/users.py - CRUD endpoints
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from .. import models, schemas
from ..dependencies import get_db

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

@router.post("/", response_model=schemas.UserResponse, status_code=201)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
    # Check for existing email
    existing = db.query(models.User).filter(
        models.User.email == user.email
    ).first()
    if existing:
        raise HTTPException(status_code=400, detail="Email already registered")

    db_user = models.User(
        email=user.email,
        name=user.name,
        hashed_password=get_password_hash(user.password),
    )
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

Async database access with SQLAlchemy 2.0:

# Async engine with asyncpg
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker

engine = create_async_engine(
    "postgresql+asyncpg://user:pass@localhost/mydb",
    pool_size=20,
    max_overflow=10,
)
AsyncSession = async_sessionmaker(engine, expire_on_commit=False)

async def get_db():
    async with AsyncSession() as session:
        yield session

@router.get("/{user_id}", response_model=schemas.UserResponse)
async def get_user(user_id: int, db = Depends(get_db)):
    result = await db.execute(
        select(models.User).where(models.User.id == user_id)
    )
    user = result.scalar_one_or_none()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user

9. Middleware & CORS

Middleware runs before and after every request. Use it for logging, timing, authentication checks, and CORS configuration:

import time
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# CORS middleware - allow your frontend to call the API
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "http://localhost:3000",     # React dev server
        "https://myapp.example.com", # Production frontend
    ],
    allow_credentials=True,
    allow_methods=["*"],   # Allow all HTTP methods
    allow_headers=["*"],   # Allow all headers
)

# Custom middleware to log request duration
@app.middleware("http")
async def add_timing_header(request: Request, call_next):
    start_time = time.perf_counter()
    response = await call_next(request)
    duration = time.perf_counter() - start_time
    response.headers["X-Response-Time"] = f"{duration:.4f}s"
    return response

# Trusted host middleware (prevent host header attacks)
from fastapi.middleware.trustedhost import TrustedHostMiddleware

app.add_middleware(
    TrustedHostMiddleware,
    allowed_hosts=["myapp.example.com", "localhost"],
)

10. Background Tasks

FastAPI's BackgroundTasks lets you run code after the response is sent — perfect for sending emails, processing uploads, or updating caches without making the client wait:

from fastapi import BackgroundTasks, FastAPI

app = FastAPI()

# Background task function
def send_welcome_email(email: str, name: str):
    # This runs after the response is sent
    print(f"Sending welcome email to {email}")
    # smtp.send(to=email, subject="Welcome!", body=f"Hi {name}...")

def write_audit_log(user_id: int, action: str):
    # Log the action to a file or database
    with open("audit.log", "a") as f:
        f.write(f"{user_id}: {action}\n")

@app.post("/users/", status_code=201)
async def create_user(
    name: str,
    email: str,
    background_tasks: BackgroundTasks,
):
    user = save_user_to_db(name, email)

    # Queue multiple background tasks
    background_tasks.add_task(send_welcome_email, email, name)
    background_tasks.add_task(write_audit_log, user.id, "user_created")

    # Response is sent immediately, tasks run after
    return {"id": user.id, "name": name}

For heavy or long-running tasks, use a proper task queue like Celery or arq instead of BackgroundTasks.

11. Testing

FastAPI provides a TestClient built on httpx that lets you test endpoints without starting a server:

# tests/test_users.py
import pytest
from fastapi.testclient import TestClient
from app.main import app
from app.database import Base, engine
from app.dependencies import get_db

# Override the database dependency with a test database
SQLALCHEMY_TEST_URL = "sqlite:///./test.db"
test_engine = create_engine(SQLALCHEMY_TEST_URL)
TestSession = sessionmaker(bind=test_engine)

def override_get_db():
    db = TestSession()
    try:
        yield db
    finally:
        db.close()

app.dependency_overrides[get_db] = override_get_db

# Create test client
client = TestClient(app)

@pytest.fixture(autouse=True)
def setup_db():
    Base.metadata.create_all(bind=test_engine)
    yield
    Base.metadata.drop_all(bind=test_engine)

def test_create_user():
    response = client.post("/users/", json={
        "name": "Alice",
        "email": "alice@example.com",
        "password": "securepass123",
    })
    assert response.status_code == 201
    data = response.json()
    assert data["name"] == "Alice"
    assert data["email"] == "alice@example.com"
    assert "password" not in data  # response_model filters it

def test_create_user_duplicate_email():
    client.post("/users/", json={
        "name": "Alice",
        "email": "alice@example.com",
        "password": "pass1",
    })
    response = client.post("/users/", json={
        "name": "Bob",
        "email": "alice@example.com",
        "password": "pass2",
    })
    assert response.status_code == 400

def test_get_user_not_found():
    response = client.get("/users/999")
    assert response.status_code == 404

Async testing with pytest-asyncio:

import pytest
from httpx import AsyncClient, ASGITransport
from app.main import app

@pytest.mark.anyio
async def test_async_root():
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as ac:
        response = await ac.get("/")
    assert response.status_code == 200
    assert response.json() == {"message": "Hello, FastAPI!"}

12. Deployment

For production, run Uvicorn behind Gunicorn for process management, and place a reverse proxy in front for SSL and static files:

# Production command: Gunicorn with Uvicorn workers
gunicorn app.main:app \
  -w 4 \
  -k uvicorn.workers.UvicornWorker \
  -b 0.0.0.0:8000 \
  --access-logfile - \
  --error-logfile -

Dockerfile for containerized deployment:

FROM python:3.12-slim

WORKDIR /app

# Install dependencies first (cached layer)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY ./app ./app

# Create non-root user
RUN adduser --disabled-password --no-create-home appuser
USER appuser

EXPOSE 8000

# Health check
HEALTHCHECK --interval=30s --timeout=3s \
  CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')"

# Start with Gunicorn + Uvicorn workers
CMD ["gunicorn", "app.main:app", \
     "-w", "4", \
     "-k", "uvicorn.workers.UvicornWorker", \
     "-b", "0.0.0.0:8000"]

Production settings checklist:

⚙ Containerize it: Follow our Docker Complete Guide and set up CI/CD with GitHub Actions.

13. Performance Tips

FastAPI is already fast, but these practices will squeeze out the best performance:

Use async for I/O-bound operations. If your endpoint calls a database, external API, or file system, make it async:

# Good: async for I/O-bound work
@app.get("/data")
async def get_data():
    async with httpx.AsyncClient() as client:
        response = await client.get("https://api.example.com/data")
    return response.json()

# Good: sync for CPU-bound work (FastAPI runs it in a thread pool)
@app.get("/compute")
def compute_heavy():
    result = expensive_calculation()  # Blocking but in thread pool
    return {"result": result}

Connection pooling is critical for database performance:

# Configure SQLAlchemy pool for production
engine = create_engine(
    DATABASE_URL,
    pool_size=20,        # Max persistent connections
    max_overflow=10,     # Extra connections when pool is full
    pool_pre_ping=True,  # Test connections before use
    pool_recycle=3600,   # Recycle connections after 1 hour
)

Response caching with a simple in-memory cache:

from functools import lru_cache
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse

# Use orjson for faster JSON serialization
app = FastAPI(default_response_class=ORJSONResponse)

# Cache configuration object (loaded once)
@lru_cache
def get_settings():
    return Settings()  # Read from env vars once, cache forever

# For HTTP caching, set Cache-Control headers
@app.get("/public-data")
async def public_data():
    data = await fetch_public_data()
    return ORJSONResponse(
        content=data,
        headers={"Cache-Control": "public, max-age=300"},
    )

Additional tips:

Frequently Asked Questions

Is FastAPI faster than Flask and Django?

Yes, FastAPI is significantly faster than both Flask and Django for API workloads. In benchmarks, FastAPI handles 2–3x more requests per second than Flask because it runs on ASGI (Uvicorn/Starlette) with native async support, while Flask and Django use synchronous WSGI. FastAPI's performance is comparable to Node.js and Go frameworks. The speed difference is most pronounced for I/O-bound workloads like database queries and external API calls, where async concurrency allows FastAPI to handle many requests simultaneously instead of blocking on each one.

How does FastAPI compare to Flask?

FastAPI and Flask serve similar purposes but differ in philosophy and features. FastAPI provides automatic request validation via Pydantic, auto-generated OpenAPI documentation, native async/await support, and dependency injection out of the box. Flask is a minimal micro-framework that requires you to add validation, documentation, and async support through extensions. FastAPI has better performance due to its ASGI foundation. Flask has a larger ecosystem of extensions and more community resources due to its longer history. Choose FastAPI for new API projects, especially if you need automatic docs and type safety. Choose Flask if you need server-side HTML rendering with Jinja2 or have an existing Flask codebase.

Can I use FastAPI with a synchronous database like SQLAlchemy?

Yes, FastAPI works with synchronous SQLAlchemy. Define your database functions as regular (non-async) functions and FastAPI will automatically run them in a thread pool so they do not block the event loop. Alternatively, use SQLAlchemy 2.0's async engine with asyncpg or aiosqlite for true async database access. For most applications, synchronous SQLAlchemy with FastAPI's thread pool is simpler and performs well. Switch to async SQLAlchemy only if you need maximum concurrency for database-heavy workloads.

How do I deploy FastAPI to production?

Deploy FastAPI with Uvicorn as the ASGI server, managed by Gunicorn for process management: run gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker with 2–4 workers per CPU core. Place a reverse proxy like Nginx or Traefik in front to handle SSL, static files, and load balancing. For containerized deployments, use the official Python slim image in Docker, install dependencies, and expose the Uvicorn port. Set environment variables for secrets and database URLs, enable structured JSON logging, and add health check endpoints.

How do I handle authentication in FastAPI?

FastAPI has built-in support for OAuth2 with the OAuth2PasswordBearer security scheme. The standard approach is JWT authentication: create a /token endpoint that validates credentials and returns a signed JWT, then use a dependency function to decode and verify the token on protected routes. Hash passwords with bcrypt via the passlib library. FastAPI's dependency injection makes it easy to create reusable auth dependencies like get_current_user that extract the user from the token. For OAuth2 with third-party providers, use authlib or httpx-oauth. FastAPI's automatic OpenAPI docs will show a login button for testing authenticated endpoints.

Conclusion

FastAPI gives you the speed of Go and Node.js with the readability and ecosystem of Python. Its combination of Pydantic validation, automatic OpenAPI docs, dependency injection, and native async support makes it the strongest choice for building modern Python APIs. Start with a single file to learn the patterns, then scale to a full project structure with routers, models, and dependencies as your application grows.

The patterns covered in this guide — type-safe models, injectable dependencies, token-based auth, and async database access — will carry you from prototype to production. FastAPI's documentation is excellent, and its growing community means answers to most questions are a search away.

⚙ Essential tools: Build and test API requests with the API Request Builder, mock endpoints with the API Mock Builder, and format JSON responses with the JSON Formatter. If your API rollback PR is blocked by required code owner review, use the Merge Queue CODEOWNERS Approval Deadlock Guide. If bypass expiry is approaching during incident rollback, follow the Merge Queue Expiry Extension Reapproval Guide. If a denied extension gets appealed, apply the Merge Queue Denial Appeal Escalation Path Guide. If rollback incidents recur across API deploys, use the Merge Queue Closure Quality Metrics Dashboard Guide to define escalation thresholds. If ACK breaches repeat in the same incident window, apply the Merge Queue Escalation Decision Cutoff Guide for hard authority-transfer cutoffs. If the cutoff window expires without executable ownership, enforce defaults with the Merge Queue Cutoff Window Expiry Enforcement Guide. After defaults are enforced, reopen queue intake only with the Merge Queue Post-Expiry Reopen Criteria Guide.

Related Resources

API Request Builder
Test your FastAPI endpoints interactively
API Mock Builder
Mock API responses for frontend development
REST API Design Guide
Best practices for designing RESTful API endpoints
Merge Queue CODEOWNERS Deadlock Guide
Incident runbook for API rollback PRs blocked by required owner approvals.
Merge Queue Expiry Extension Reapproval Guide
Reapprove API rollback bypass windows safely when validation runs outlast original expiry.
Merge Queue Denial Appeal Escalation Path
Run appeal escalation with strict timestamps when denied rollback extensions are challenged.
Merge Queue Closure Quality Metrics Dashboard
Measure recurring rollback incident risk with explicit KPI thresholds and trigger rules.
Merge Queue Post-Expiry Reopen Criteria Guide
Objective reopen gates and owner sign-off policy after expiry defaults are enforced.
Django Complete Guide
Compare FastAPI with Django's batteries-included approach
Flask Web Framework Guide
Learn Flask, Python's lightweight micro-framework
Node.js Express API Guide
Compare FastAPI with Express for API development