fastapi
Standardizes FastAPI development: schemas, auth, testing, and dependency injection.
Install
mkdir -p .claude/skills/fastapi-kid-sid && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/11005" && unzip -o skill.zip -d .claude/skills/fastapi-kid-sid && rm skill.zipInstalls to .claude/skills/fastapi-kid-sid
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use when structuring a FastAPI application, designing dependency injection chains, defining Pydantic v2 schemas, adding JWT authentication, or writing async route tests with httpx.Key capabilities
- →Structure FastAPI applications
- →Design dependency injection
- →Define Pydantic v2 schemas
- →Write async route tests
How it works
It applies layered architecture patterns and dependency injection to build reliable FastAPI services.
Inputs & outputs
When to use fastapi
- →Structuring fastapi apps
- →Implementing JWT auth
- →Writing async route tests
About this skill
FastAPI Patterns
Modern FastAPI (0.100+) with Pydantic v2, async-first, and typed throughout.
When to Activate
- Structuring a FastAPI app with routers and layered architecture
- Designing dependency injection chains with
Depends - Defining Pydantic v2 request/response schemas
- Handling errors, custom exception handlers, or middleware
- Adding authentication (OAuth2, JWT, API keys)
- Writing background tasks or startup/shutdown logic
- Testing FastAPI routes with
TestClientor asynchttpx
Project Structure
src/
├── api/
│ ├── app.py # create_app(), register routers + middleware
│ ├── dependencies.py # shared Depends (db session, current user, etc.)
│ ├── middleware.py # CORS, logging, request ID
│ └── routes/
│ ├── users.py
│ └── orders.py
├── domain/
│ ├── entities/ # Pure Pydantic models — no ORM, no HTTP
│ ├── use_cases/ # Business logic — orchestrates services
│ └── repositories/ # Abstract interfaces (Protocol or ABC)
├── adapters/
│ ├── database/ # SQLAlchemy models + session factory
│ ├── crud/ # Concrete repository implementations
│ └── external/ # Third-party HTTP clients
├── config/
│ ├── settings.py # Pydantic Settings (env vars)
│ └── dependencies.py # App-wide singletons (DB engine, Redis, etc.)
└── main.py # uvicorn entry point
App Factory
# api/app.py
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from config.dependencies import GlobalDependencies
from api.routes import users, orders
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: initialize singletons, DB pools, caches
await GlobalDependencies.initialize()
yield
# Shutdown: close connections cleanly
await GlobalDependencies.close()
def create_app() -> FastAPI:
app = FastAPI(
title="My API",
version="1.0.0",
docs_url="/swagger",
redoc_url="/api",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:3000"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(users.router, prefix="/api/v1/users", tags=["users"])
app.include_router(orders.router, prefix="/api/v1/orders", tags=["orders"])
return app
APIRouter
# api/routes/users.py
from fastapi import APIRouter, Depends, HTTPException, status
from api.dependencies import get_current_user, get_db_session
from api.schemas.users import UserResponse, CreateUserRequest
from domain.use_cases.users import CreateUserUseCase
from domain.entities.user import User
router = APIRouter()
@router.get("/", response_model=list[UserResponse])
async def list_users(
skip: int = 0,
limit: int = 100,
session=Depends(get_db_session),
):
return await UserCRUD(session).list(skip=skip, limit=limit)
@router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_user(
body: CreateUserRequest,
use_case: CreateUserUseCase = Depends(get_create_user_use_case),
):
return await use_case.execute(body)
@router.get("/{user_id}", response_model=UserResponse)
async def get_user(user_id: str, session=Depends(get_db_session)):
user = await UserCRUD(session).get(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(
user_id: str,
_current_user: User = Depends(get_current_user), # requires auth
session=Depends(get_db_session),
):
await UserCRUD(session).delete(user_id)
Dependency Injection
# api/dependencies.py
from fastapi import Depends, Header, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from config.dependencies import GlobalDependencies
async def get_db_session() -> AsyncSession:
async with GlobalDependencies.db_engine.begin() as session:
yield session # yields inside with-block; rolls back on exception
async def get_api_key(x_api_key: str = Header(...)) -> str:
if x_api_key not in GlobalDependencies.valid_keys:
raise HTTPException(status_code=403, detail="Invalid API key")
return x_api_key
async def get_current_user(
token: str = Depends(oauth2_scheme),
session: AsyncSession = Depends(get_db_session),
) -> User:
payload = decode_jwt(token) # raises 401 on bad token
user = await UserCRUD(session).get(payload["sub"])
if not user:
raise HTTPException(status_code=401, detail="User not found")
return user
# Chain dependencies — get_create_user_use_case depends on get_db_session
def get_create_user_use_case(
session: AsyncSession = Depends(get_db_session),
) -> CreateUserUseCase:
return CreateUserUseCase(repo=UserRepo(session))
Key rules:
yield-based dependencies run cleanup after the response is sent- FastAPI caches dependencies within a single request —
get_db_sessioncalled 3 times in one request returns the same session - Use
Depends(get_current_user)as a parameter to require auth on a route
Pydantic v2 Schemas
# api/schemas/users.py
from pydantic import BaseModel, EmailStr, Field, field_validator, model_validator
from datetime import datetime
from typing import Annotated
UserId = Annotated[str, Field(min_length=1, description="User UUID")]
class CreateUserRequest(BaseModel):
name: str = Field(min_length=1, max_length=100)
email: EmailStr
role: Literal["admin", "user"] = "user"
age: int = Field(ge=0, le=150)
@field_validator("name")
@classmethod
def strip_name(cls, v: str) -> str:
return v.strip()
@model_validator(mode="after")
def admin_must_have_age(self) -> "CreateUserRequest":
if self.role == "admin" and self.age < 18:
raise ValueError("Admins must be 18+")
return self
class UserResponse(BaseModel):
id: UserId
name: str
email: EmailStr
created_at: datetime
model_config = ConfigDict(from_attributes=True) # allows ORM → schema conversion
# Nested schemas
class OrderWithUserResponse(BaseModel):
id: str
total: float
user: UserResponse # nested
items: list[OrderItemResponse]
Settings (Pydantic Settings)
# config/settings.py
from pydantic_settings import BaseSettings, SettingsConfigDict
from functools import lru_cache
class Settings(BaseSettings):
environment: str = "development"
database_url: str
redis_url: str = "redis://localhost:6379"
secret_key: str
allowed_origins: list[str] = ["http://localhost:3000"]
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
)
@lru_cache
def get_settings() -> Settings:
return Settings()
# In dependency:
def get_settings_dep(settings: Settings = Depends(get_settings)) -> Settings:
return settings
Error Handling
# domain/exceptions.py
class ClientError(Exception):
"""400 — bad input, caller's fault"""
def __init__(self, message: str): self.message = message
class NotFoundError(Exception):
"""404"""
def __init__(self, resource: str, id: str):
self.message = f"{resource} '{id}' not found"
class ServiceError(Exception):
"""500 — internal failure"""
# api/app.py — register handlers
from fastapi import Request
from fastapi.responses import JSONResponse
@app.exception_handler(ClientError)
async def client_error_handler(request: Request, exc: ClientError):
return JSONResponse(status_code=400, content={"detail": exc.message})
@app.exception_handler(NotFoundError)
async def not_found_handler(request: Request, exc: NotFoundError):
return JSONResponse(status_code=404, content={"detail": exc.message})
@app.exception_handler(ServiceError)
async def service_error_handler(request: Request, exc: ServiceError):
return JSONResponse(status_code=500, content={"detail": "Internal error"})
Never raise HTTPException inside use cases — only in route handlers or dependencies.
Middleware
# api/middleware.py
import uuid, time
from fastapi import Request
async def request_id_middleware(request: Request, call_next):
request_id = request.headers.get("x-request-id", uuid.uuid4().hex)
request.state.request_id = request_id
start = time.perf_counter()
response = await call_next(request)
duration = time.perf_counter() - start
response.headers["x-request-id"] = request_id
response.headers["x-response-time"] = f"{duration:.3f}s"
return response
# Register as BaseHTTPMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
app.add_middleware(BaseHTTPMiddleware, dispatch=request_id_middleware)
Background Tasks
from fastapi import BackgroundTasks
@router.post("/users/")
async def create_user(
body: CreateUserRequest,
background_tasks: BackgroundTasks,
session=Depends(get_db_session),
):
user = await UserCRUD(session).create(body)
# runs after response is sent — good for emails, webhooks, cache invalidation
background_tasks.add_task(send_welcome_email, user.email, user.name)
return user
Use background tasks for fire-and-forget work. For durable/retryable work, use a task queue (Celery, ARQ, Temporal).
Authentication (JWT + OAuth2)
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
import jwt
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")
@router.post("/auth/token")
async def login(form: OAuth2PasswordRequestForm = Depends(), session=Depends(get_db_session)):
user = await authenticate_user(form.user
---
*Content truncated.*
When not to use it
- →Synchronous-only applications
- →Non-Python backend development
Prerequisites
Limitations
- →Requires understanding of async Python
- →Not for non-web applications
How it compares
It enforces modern, async-first patterns and Pydantic v2 schemas for type safety.
Compared to similar skills
fastapi side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| fastapi (this skill) | 0 | 3mo | Review | Intermediate |
| fastapi-templates | 520 | 2mo | No flags | Intermediate |
| fastapi-pro | 79 | 3mo | No flags | Advanced |
| fastapi-router-py | 5 | 26d | No flags | Beginner |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
fastapi-pro
sickn33
Build high-performance async APIs with FastAPI, SQLAlchemy 2.0, and Pydantic V2. Master microservices, WebSockets, and modern Python async patterns. Use PROACTIVELY for FastAPI development, async optimization, or API architecture.
fastapi-router-py
microsoft
Create FastAPI routers with CRUD operations, authentication dependencies, and proper response models. Use when building REST API endpoints, creating new routes, implementing CRUD operations, or adding authenticated endpoints in FastAPI applications.
pydantic-models-py
microsoft
Create Pydantic models following the multi-model pattern with Base, Create, Update, Response, and InDB variants. Use when defining API request/response schemas, database models, or data validation in Python applications using Pydantic v2.
backend-architect
sickn33
Expert backend architect specializing in scalable API design, microservices architecture, and distributed systems. Masters REST/GraphQL/gRPC APIs, event-driven architectures, service mesh patterns, and modern backend frameworks. Handles service boundary definition, inter-service communication, resilience patterns, and observability. Use PROACTIVELY when creating new backend services or APIs.
supabase-python
alinaqi
FastAPI with Supabase and SQLAlchemy/SQLModel