app-scaffolding
Original:🇺🇸 English
Translated
4 scriptsChecked / no sensitive code detected
Guides the agent through scaffolding and building FastAPI applications, including project structure, API routes, request/response models, path and query parameters, dependency injection, middleware, error handling, and boilerplate generation. Triggered when the user asks to "scaffold a FastAPI project", "create a FastAPI app", "add an API endpoint", "create a router", "add middleware", "implement dependency injection", "handle errors", "set up CORS", "create background tasks", "implement WebSocket", "structure a FastAPI project", "generate boilerplate", or "add authentication".
7installs
Added on
NPX Install
npx skill4agent add ingpdw/pdw-python-dev-tool app-scaffoldingTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →FastAPI Skill
Overview
FastAPI is a modern, high-performance async Python web framework for building APIs. It
leverages Python type hints and Pydantic for automatic validation, serialization, and
OpenAPI documentation generation. FastAPI runs on ASGI servers (Uvicorn, Hypercorn) and
provides first-class support for async/await, dependency injection, and WebSockets.
Key characteristics:
- Automatic interactive API docs (Swagger UI at , ReDoc at
/docs)/redoc - Type-driven request validation and response serialization via Pydantic
- Native async support with full sync fallback
- Dependency injection system for shared logic and resource management
- Standards-based: OpenAPI 3.1, JSON Schema
Project Structure
Organize FastAPI projects with a clear separation of concerns:
project/
├── app/
│ ├── __init__.py
│ ├── main.py # Application factory and lifespan
│ ├── config.py # Settings via pydantic-settings
│ ├── dependencies.py # Shared dependencies
│ ├── models.py # SQLAlchemy / ORM models
│ ├── schemas.py # Pydantic request/response schemas
│ ├── routers/
│ │ ├── __init__.py # Router registration
│ │ ├── users.py
│ │ ├── items.py
│ │ └── health.py
│ ├── services/ # Business logic layer
│ ├── middleware/ # Custom middleware
│ └── exceptions.py # Custom exception handlers
├── tests/
│ ├── conftest.py
│ ├── test_users.py
│ └── test_items.py
├── alembic/ # Database migrations
├── pyproject.toml
└── .envSee for a ready-to-use scaffold.
assets/app-template/Application Factory and Lifespan
Use the async context manager lifespan pattern (the decorator is deprecated):
on_eventpython
from contextlib import asynccontextmanager
from fastapi import FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup: initialize resources
app.state.db_pool = await create_db_pool()
app.state.http_client = httpx.AsyncClient()
yield
# Shutdown: release resources
await app.state.http_client.aclose()
await app.state.db_pool.close()
def create_app() -> FastAPI:
app = FastAPI(
title="My API",
version="0.1.0",
lifespan=lifespan,
)
app.include_router(users_router)
app.include_router(items_router)
return app
app = create_app()Route Definition
Define routes with HTTP method decorators. Use type-annotated parameters for automatic
validation and documentation.
Path Parameters
python
@app.get("/users/{user_id}")
async def get_user(user_id: int) -> User:
...Query Parameters
python
@app.get("/items")
async def list_items(skip: int = 0, limit: int = 20, q: str | None = None):
...Request Body
python
from pydantic import BaseModel
class ItemCreate(BaseModel):
name: str
price: float
description: str | None = None
@app.post("/items", status_code=201)
async def create_item(item: ItemCreate) -> Item:
...Multiple Parameter Sources
python
@app.put("/items/{item_id}")
async def update_item(
item_id: int, # path
item: ItemUpdate, # body
q: str | None = None, # query
x_token: Annotated[str, Header()], # header
):
...Response Models
Control response shape and status codes:
python
@app.post("/users", response_model=UserOut, status_code=201)
async def create_user(user: UserCreate):
...
@app.get("/report", response_class=HTMLResponse)
async def get_report():
return "<html>...</html>"Use to omit fields not explicitly set, and
to strip sensitive fields.
response_model_exclude_unset=Trueresponse_model_exclude={"password"}Router Organization
Split endpoints into routers for modularity:
python
# app/routers/users.py
from fastapi import APIRouter
router = APIRouter(prefix="/users", tags=["users"])
@router.get("/")
async def list_users():
...
@router.get("/{user_id}")
async def get_user(user_id: int):
...Register routers in the application factory:
python
from app.routers import users, items
app.include_router(users.router)
app.include_router(items.router, prefix="/api/v1")Apply shared dependencies to all routes on a router:
python
router = APIRouter(
prefix="/admin",
tags=["admin"],
dependencies=[Depends(require_admin)],
)Dependency Injection
Use to declare reusable, composable dependencies. Dependencies can be
functions, async functions, or callable classes.
Depends()python
from fastapi import Depends
from typing import Annotated
async def get_db():
async with async_session() as session:
yield session
DbSession = Annotated[AsyncSession, Depends(get_db)]
async def get_current_user(db: DbSession, token: str = Depends(oauth2_scheme)) -> User:
...
CurrentUser = Annotated[User, Depends(get_current_user)]
@app.get("/me")
async def read_me(user: CurrentUser):
return userYield dependencies execute cleanup after the response is sent, making them ideal for
database sessions, file handles, and other resources that require teardown.
See for advanced patterns including parameterized
dependencies, class-based dependencies, and testing overrides.
references/dependency-injection.mdRequest and Response Models with Pydantic
Define strict, validated schemas using Pydantic models. Separate input and output
schemas to control what is accepted vs. returned:
python
class UserBase(BaseModel):
email: EmailStr
name: str
class UserCreate(UserBase):
password: str
class UserOut(UserBase):
id: int
created_at: datetime
model_config = ConfigDict(from_attributes=True)Cross-reference: see the pydantic skill for comprehensive model patterns, custom
validators, and serialization options.
Lifespan Events
The lifespan async context manager replaces the deprecated
and decorators. Everything before runs at startup;
everything after runs at shutdown.
@app.on_event("startup")@app.on_event("shutdown")yieldStore shared resources on so dependencies can access them:
app.statepython
@asynccontextmanager
async def lifespan(app: FastAPI):
app.state.redis = await aioredis.from_url("redis://localhost")
yield
await app.state.redis.close()Background Tasks
Enqueue lightweight work to run after the response is returned:
python
from fastapi import BackgroundTasks
def send_notification(email: str, message: str):
# blocking or async work
...
@app.post("/orders")
async def create_order(order: OrderCreate, background_tasks: BackgroundTasks):
result = await process_order(order)
background_tasks.add_task(send_notification, order.email, "Order confirmed")
return resultFor heavier workloads, offload to a task queue (Celery, ARQ, or Dramatiq) instead.
Error Handling
HTTPException
python
from fastapi import HTTPException
@app.get("/items/{item_id}")
async def get_item(item_id: int):
item = await fetch_item(item_id)
if not item:
raise HTTPException(status_code=404, detail="Item not found")
return itemCustom Exception Handlers
python
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
class ItemNotFoundError(Exception):
def __init__(self, item_id: int):
self.item_id = item_id
@app.exception_handler(ItemNotFoundError)
async def item_not_found_handler(request, exc):
return JSONResponse(
status_code=404,
content={"detail": f"Item {exc.item_id} not found"},
)
@app.exception_handler(RequestValidationError)
async def validation_handler(request, exc):
return JSONResponse(
status_code=422,
content={"detail": exc.errors(), "body": exc.body},
)CORS Configuration
python
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://example.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)Never use with in production. See
for detailed CORS guidance and other middleware patterns.
allow_origins=["*"]allow_credentials=Truereferences/middleware.mdTesting
Use for synchronous tests or for async tests.
Override dependencies to inject mocks:
TestClienthttpx.AsyncClientpython
from fastapi.testclient import TestClient
def test_read_items():
app.dependency_overrides[get_db] = lambda: mock_db
client = TestClient(app)
response = client.get("/items")
assert response.status_code == 200
app.dependency_overrides.clear()Async test with :
httpxpython
import pytest
from httpx import ASGITransport, AsyncClient
@pytest.mark.anyio
async def test_create_item():
async with AsyncClient(
transport=ASGITransport(app=app), base_url="http://test"
) as client:
response = await client.post("/items", json={"name": "Widget", "price": 9.99})
assert response.status_code == 201Further Reading
- -- advanced routing, file uploads, WebSockets, SSE
references/routing-patterns.md - -- middleware patterns, ordering, custom middleware
references/middleware.md - -- DI composition, testing, scoping
references/dependency-injection.md - -- production-ready project scaffold
assets/app-template/
Cross-references:
- pydantic skill -- model definitions, validators, serialization
- async-patterns skill -- async/await best practices, concurrency
- uvicorn skill -- ASGI server configuration and deployment