← All skills
Engineering https://ai-skills-vault.pages.dev/skills/api-builder-fastapi.md

API Builder (FastAPI)

Contract-first backend with auth, idempotency and observability built in.

Download .md All skills
Install URLhttps://ai-skills-vault.pages.dev/skills/api-builder-fastapi.md
Install prompt tap to copy
Read the skill at https://ai-skills-vault.pages.dev/skills/api-builder-fastapi.md and install it as a skill in your agent. Follow it exactly, including its checklists. Then ask me the questions it requires and do the work.

Most APIs fail on the same five things: unclear contracts, no authorisation model, no idempotency, no pagination discipline, and no observability. This skill closes all five before launch.

When to use this skill

Stage 1 - Contract before code

Write the OpenAPI shape first, or the resource table:

ResourceMethodPathAuthSuccessErrors
userGET/v1/users/{id}bearer200401, 403, 404
userPOST/v1/usersbearer + admin201400, 401, 403, 409
orderPOST/v1/ordersbearer201400, 402, 409, 422

Rules that prevent rewrites: version in the path (/v1), plural nouns, no verbs in paths, snake_case JSON, ISO-8601 UTC timestamps, ids as UUID or ULID strings, money as integer minor units plus a currency code (never floats).

Stage 2 - Project layout

app/
  main.py            app factory, middleware, routers
  core/              config, security, logging, errors
  db/                engine, session, migrations
  models/            SQLAlchemy models
  schemas/           pydantic request/response models
  api/v1/            routers per resource
  services/          business logic - no HTTP here
  tests/

Hard rule: routers validate and delegate; services contain logic; models touch the database. No SQL in a router, no Request object in a service.

Stage 3 - Validation and error model

from pydantic import BaseModel, EmailStr, Field
class UserCreate(BaseModel):
    email: EmailStr
    name: str = Field(min_length=1, max_length=80)
    plan: Literal["free", "pro"] = "free"

One error envelope for the whole API, always:

{"error": {"code": "email_taken", "message": "That email is already registered.",
           "field": "email", "request_id": "req_01H..."}}

Stage 4 - Auth and authorisation

  1. Authentication: bearer JWT or opaque session in an httpOnly cookie. Short-lived access token (15 min) + refresh token rotation.
  2. Passwords: argon2id, never bcrypt-with-default-cost, never MD5/SHA.
  3. Authorisation: a dependency that loads the resource and checks ownership or role on the server, per endpoint. A check in the UI is not a check.
def get_owned_order(order_id: str, user=Depends(current_user), db=Depends(get_db)) -> Order:
    order = db.get(Order, order_id)
    if not order:
        raise HTTPException(404, "order_not_found")
    if order.user_id != user.id and not user.is_admin:
        raise HTTPException(403, "forbidden")
    return order
  1. Rate limit per user and per IP on auth and write endpoints. 429 with Retry-After.
  2. Never trust client-supplied role, price, total or user id. Derive them server-side.

Stage 5 - Idempotency and safety on writes

Stage 6 - Pagination, filtering, sorting

@router.get("/orders")
def list_orders(cursor: str | None = None, limit: int = Query(20, le=100), ...):

Stage 7 - Database and migrations

Stage 8 - Tests

  1. Unit tests for services with a fake repository - fast, no DB.
  2. Integration tests against a real ephemeral Postgres (testcontainers or a docker service) - catches what mocks hide.
  3. Contract tests: every endpoint's success and error shape asserted against the OpenAPI schema.
  4. Auth tests: unauthenticated, wrong user, admin, expired token, for each protected route.
  5. One load smoke test at 10x expected traffic on the heaviest read path.

Target: the auth-and-write paths have 100% of their branches covered. Chasing a global coverage number is theatre.

Stage 9 - Observability and operations

Stage 10 - Deploy checklist

Failure modes

SymptomCauseFix
500s under loadPool exhaustion / N+1 queriesPool sizing, eager loading, indexes
Duplicate chargesNo idempotency keyAdd key + unique constraint
Slow list endpointOFFSET on a big tableCursor pagination
Data leakMissing ownership checkCentral ownership dependency, test it
Broken clients after a changeUnversioned breaking change/v2, deprecate with a sunset header

Copy-ready agent prompt

Read the skill at the URL above. Start with the Stage 1 resource table for my domain and get my approval. Then scaffold the layout, write pydantic schemas, services with the logic, routers that only delegate, one error envelope, an ownership-check dependency, cursor pagination, Alembic migrations and tests including auth failure cases. Finish with the Stage 10 deploy checklist and tell me honestly which items are not done.
Copied