smithery.ai

fastapi-dev

FastAPI endpoint development with Pydantic validation, proper error handling, and OpenAPI documentation. Use when creating or modifying API endpoints, routers, or schemas.

First seen Apr 4, 2026

Installation

$ npx skills add https://smithery.ai

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery.ai · top by installs.

npx skills add https://smithery.ai

Browse all from smithery.ai

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Allowed toolsRead, Edit, Bash, Grep, Glob

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 5,254 B
  • docs SUMMARY.md 190 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 1 installs

SKILL.md

FastAPI Development Standards

This skill guides development of FastAPI endpoints for the E-Signature Platform API.

Endpoint Implementation Checklist

  1. Pydantic Models: Always define request/response schemas in app/schemas/
  2. Error Handling: Use error codes from esig-design.md Error Code Catalog
  3. Authentication: Use getcurrentuser dependency for protected routes
  4. Validation: Implement constraints from esig-design.md (e.g., name 1-255 chars)
  5. Idempotency: Create endpoints accept Idempotency-Key header
  6. Tests: Write success, validation error, and auth error test cases

Error Response Format

All errors must follow the standard format from esig-design.md:

from fastapi import HTTPException

# Standard error response
raise HTTPException(
    status_code=404,
    detail={
        "error": {
            "code": "ENVELOPE_NOT_FOUND",
            "message": "Envelope does not exist",
            "details": {}
        }
    }
)

Error Code Reference (esig-design.md)

Code HTTP Status Use Case
AUTHINVALIDCREDENTIALS 401 Wrong email/password
AUTHTOKENEXPIRED 401 Access token expired
AUTHTOKENINVALID 401 Malformed token
AUTHREFRESHTOKEN_INVALID 401 Bad refresh token
AUTHEMAILNOT_VERIFIED 403 Email verification required
ENVELOPENOTFOUND 404 Envelope doesn't exist
ENVELOPENOTOWNED 403 Can't access others' envelope
ENVELOPEINVALIDSTATE 403 Action not allowed in current state
DOCUMENTNOTFOUND 404 Document doesn't exist
RECIPIENTNOTFOUND 404 Recipient doesn't exist
RECIPIENTNOTAUTHORIZED 403 Invalid signing token
SIGNINGORDERVIOLATION 403 Not recipient's turn
VALIDATION_ERROR 422 Request body validation failed
FILETOOLARGE 413 File exceeds size limit
FILETYPEINVALID 422 File type not allowed
REQUIREDFIELDSMISSING 422 Required fields not filled

Authentication Patterns

from app.dependencies import get_current_user, get_db
from app.models.user import User
from sqlalchemy.ext.asyncio import AsyncSession

# Protected endpoint (any authenticated user)
@router.get("/envelopes")
async def list_envelopes(
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    ...

# Optional auth (for public signing endpoints)
@router.get("/signing/{token}")
async def get_signing_session(
    token: str,
    db: AsyncSession = Depends(get_db)
):
    # Validate signing token instead of JWT
    ...

Pagination Pattern

Use cursor-based pagination:

from app.schemas.common import PaginatedResponse

@router.get("/envelopes", response_model=PaginatedResponse[EnvelopeListItem])
async def list_envelopes(
    limit: int = Query(default=20, ge=1, le=100),
    cursor: str | None = Query(default=None),
    status: str | None = Query(default=None),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    # Decode cursor, query with limit+1, encode next_cursor
    ...
    return {
        "items": envelopes[:limit],
        "next_cursor": encode_cursor(envelopes[limit].id) if len(envelopes) > limit else None
    }

Idempotency Pattern

from app.utils.idempotency import check_idempotency, store_idempotency

@router.post("/envelopes")
async def create_envelope(
    envelope_data: EnvelopeCreate,
    idempotency_key: str | None = Header(default=None, alias="Idempotency-Key"),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db)
):
    # Check for existing response
    if idempotency_key:
        cached = await check_idempotency(db, idempotency_key, user.id)
        if cached:
            return cached

    # Process request
    envelope = await create_envelope_impl(db, user.id, envelope_data)

    # Store for idempotency
    if idempotency_key:
        await store_idempotency(db, idempotency_key, user.id, envelope)

    return envelope

Validation Constraints (from esig-design.md)

Field Constraint
email Valid format, max 255 chars
name (user/recipient) 1-100 chars
name (envelope) 1-255 chars
message max 10000 chars
xpercent, ypercent 0-100
widthpercent, heightpercent 0-100
File size (PDF) max 10MB
File size (signature image) max 500KB

After Implementation

Run these commands after creating/modifying endpoints:

# Format code
ruff format backend/

# Type check
uv run mypy app/

# Run tests for the module
uv run pytest tests/test_<module>.py -v

File Organization

app/
├── routers/<resource>.py    # Endpoint definitions
├── schemas/<resource>.py    # Pydantic models
├── models/<resource>.py     # SQLAlchemy models
└── services/<resource>.py   # Business logic (if complex)