Verified against GitHub Copilot Chat · 2026-07-20
Scaffold a FastAPI endpoint with real validation and status codes
A prompt that turns an endpoint requirement into a complete FastAPI route with Pydantic v2 models, correct HTTP status codes, and dependency-injected services, instead of a bare route stub returning a dict.
The prompt
Ready to copy — highlighted parts are example details you can swap.
Scaffold one FastAPI endpoint. This is a real service route, not a toy example — include validation, correct status codes, and dependency injection. ENDPOINT REQUIREMENT POST a new subscription for a user: takes plan_id and payment_method_id, returns the created subscription, 404 if plan_id doesn't exist, 409 if the user already has an active subscription. CONVENTIONS TO FOLLOW - Use APIRouter, mounted under /api/v1, resource name subscriptions. - Request and response bodies are Pydantic v2 models (BaseModel, not raw dicts) with Field constraints matching the requirement — don't accept a wider type than the spec allows. - Use response_model on the route decorator, and the correct status code from fastapi.status (201 for creation, 204 for delete with no body, 404 when a lookup fails — 422 is Pydantic's job, not yours to hand-roll). - Inject dependencies (DB session, current user, etc.) via Depends(...), never instantiate them inside the handler. Assume this dependency already exists and is wired: get_db_session() -> AsyncSession, already defined in app/api/deps.py. - Auth: requires an authenticated user via get_current_user(). If it's "none," don't add an auth dependency; don't invent one either. - All I/O is async def. If a called function is genuinely synchronous or CPU-bound, say so explicitly and wrap it with run_in_threadpool rather than blocking the event loop silently. - Raise HTTPException with a specific status and detail message for every failure path named in the requirement — don't let an unhandled case fall through to a generic 500. OUTPUT FORMAT 1. The Pydantic request/response models. 2. The route function. 3. A one-line note per status code used, mapping it to the requirement it satisfies.
Customize the highlighted detailsoptional — the prompt above already works
Why this works
FastAPI derives its automatic OpenAPI schema and request validation directly from the type hints on the route function and the Pydantic models it declares, so a scaffold that skips response_model or accepts a raw dict quietly loses the framework's main benefit — it still runs, but the generated docs and validation are wrong or missing. Naming the exact status codes per failure path (404 for a missing lookup, 409 for a conflict) stops the common default of returning 200 with an error message in the body, which breaks every client that checks the HTTP status rather than parsing the payload. The explicit instruction to wrap blocking calls with run_in_threadpool addresses FastAPI's single most common production bug: an async def handler that calls a synchronous, blocking function directly, which stalls the entire event loop for every other request being served by that worker, not just the slow one.
What you get back
class SubscriptionCreate(BaseModel): plan_id: UUID payment_method_id: str = Field(min_length=1) class SubscriptionOut(BaseModel): id: UUID plan_id: UUID status: str @router.post("/subscriptions", response_model=SubscriptionOut, status_code=status.HTTP_201_CREATED) async def create_subscription( body: SubscriptionCreate, db: AsyncSession = Depends(get_db_session), current_user: User = Depends(get_current_user), ) -> SubscriptionOut: plan = await get_plan(db, body.plan_id) if plan is None: raise HTTPException(status_code=404, detail="Plan not found") if await user_has_active_subscription(db, current_user.id): raise HTTPException(status_code=409, detail="User already has an active subscription") subscription = await create_subscription_record(db, current_user.id, body) return subscription Status codes: 201 on success (subscription created); 404 when plan_id doesn't match a real plan; 409 when the user already has an active subscription.
Verified against
GitHub Copilot Chat 1.260 (VS Code) · 2026-07-20
Cursor 2.1 · 2026-07-22
Changelog
- 2026-07-22 — Initial publish, verified against GitHub Copilot Chat and Cursor 2.1 on FastAPI 0.115.
Need this built into your business?
If a prompt isn't enough — custom software, built and maintained for you — that's Scult's day job.
EXPLORE CUSTOM SOFTWARE

