smithery.ai

python-fastapi

FastAPI framework, pydantic models, dependency injection, API design

First seen Mar 12, 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 Declared

Skill metadata

Parsed from SKILL.md frontmatter.

LicenseMIT
Compatibilityopencode
Declared agents opencode
More metadata
audience
python-developers
focus
web-frameworks

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 11,824 B
  • docs SUMMARY.md 90 B

History

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

SKILL.md

What I do

I provide guidance on building APIs with FastAPI, including:

  • Pydantic models for validation
  • Dependency injection patterns
  • Route organization and tags
  • API versioning strategies
  • Error handling and exception handlers
  • Background tasks and async endpoints
  • Testing FastAPI apps with TestClient
  • OpenAPI/Swagger documentation
  • Security and authentication
  • Middleware and CORS
  • WebSockets and streaming

When to use me

Use me when:

  • Building RESTful APIs with FastAPI
  • Designing pydantic models and schemas
  • Implementing dependency injection
  • Setting up authentication and authorization
  • Writing API tests
  • Configuring OpenAPI documentation
  • Handling async endpoints
  • Implementing middleware
  • Working with websockets

Best Practices

✅ Use Pydantic Models for Validation

from pydantic import BaseModel, EmailStr, Field, validator
from typing import Optional
from datetime import datetime

class UserCreate(BaseModel):
    """Schema for user creation."""
    name: str = Field(..., min_length=1, max_length=100)
    email: EmailStr
    age: Optional[int] = Field(None, ge=0, le=150)

    @validator("name")
    def name_must_not_contain_numbers(cls, v: str) -> str:
        """Validate name doesn't contain numbers."""
        if any(c.isdigit() for c in v):
            raise ValueError("name cannot contain numbers")
        return v

class UserResponse(BaseModel):
    """Schema for user response."""
    id: int
    name: str
    email: str
    age: Optional[int] = None
    created_at: datetime

    class Config:
        """Pydantic config."""
        from_attributes = True

✅ Dependency Injection with Type Hints

from fastapi import FastAPI, Depends, HTTPException, status
from typing import Protocol, Annotated

app = FastAPI()

class UserRepository(Protocol):
    """Protocol for user repository."""
    async def get_user(self, user_id: int) -> Optional[User]: ...

async def get_db_session() -> AsyncSession:
    """Dependency for database session."""
    async with async_session() as session:
        yield session

async def get_user_repository(
    session: AsyncSession = Depends(get_db_session)
) -> UserRepository:
    """Dependency for user repository."""
    return SQLUserRepository(session)

# Use Annotated for cleaner dependencies
from fastapi import Depends
from typing import Annotated

DB = Annotated[AsyncSession, Depends(get_db_session)]
UserRepo = Annotated[UserRepository, Depends(get_user_repository)]

@app.get("/users/{user_id}")
async def get_user(
    user_id: int,
    repo: UserRepo
) -> UserResponse:
    """Get a user by ID with dependency injection."""
    user = await repo.get_user(user_id)
    if user is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    return UserResponse.from_orm(user)

✅ Route Organization and Tags

from fastapi import APIRouter
from typing import List

router = APIRouter(prefix="/api/v1/users", tags=["users"])

@router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def create_user(
    user_data: UserCreate,
    repo: UserRepo
) -> UserResponse:
    """Create a new user."""
    user = await repo.create_user(user_data)
    return UserResponse.from_orm(user)

@router.get("/", response_model=List[UserResponse])
async def list_users(
    skip: int = 0,
    limit: int = 100,
    repo: UserRepo
) -> List[UserResponse]:
    """List all users with pagination."""
    users = await repo.list_users(skip=skip, limit=limit)
    return [UserResponse.from_orm(u) for u in users]

# Include router in main app
app = FastAPI()
app.include_router(router)

✅ Proper Error Handling

from fastapi import Request
from fastapi.responses import JSONResponse

class UserNotFoundError(Exception):
    """Exception for user not found."""
    pass

@app.exception_handler(UserNotFoundError)
async def user_not_found_handler(
    request: Request,
    exc: UserNotFoundError
) -> JSONResponse:
    """Handle user not found exceptions."""
    return JSONResponse(
        status_code=status.HTTP_404_NOT_FOUND,
        content={"detail": "User not found"},
    )

@app.get("/users/{user_id}")
async def get_user(user_id: int, repo: UserRepo) -> UserResponse:
    """Get user with custom exception."""
    user = await repo.get_user(user_id)
    if user is None:
        raise UserNotFoundError()
    return UserResponse.from_orm(user)

✅ Async Endpoints with Background Tasks

from fastapi import BackgroundTasks

def send_welcome_email(email: str, name: str) -> None:
    """Send welcome email (background task)."""
    # Send email synchronously (runs in background)
    send_email(email, f"Welcome, {name}!")

@app.post("/users/")
async def create_user(
    user_data: UserCreate,
    repo: UserRepo,
    background_tasks: BackgroundTasks
) -> UserResponse:
    """Create user and send welcome email in background."""
    user = await repo.create_user(user_data)

    # Schedule background task
    background_tasks.add_task(
        send_welcome_email,
        user_data.email,
        user_data.name
    )

    return UserResponse.from_orm(user)

✅ API Versioning

from fastapi import APIRouter

# Version 1
v1_router = APIRouter(prefix="/api/v1", tags=["v1"])

@v1_router.get("/users/{user_id}")
async def get_user_v1(user_id: int, repo: UserRepo) -> UserResponseV1:
    """Get user (v1)."""
    user = await repo.get_user(user_id)
    return UserResponseV1.from_orm(user)

# Version 2
v2_router = APIRouter(prefix="/api/v2", tags=["v2"])

@v2_router.get("/users/{user_id}")
async def get_user_v2(user_id: int, repo: UserRepo) -> UserResponseV2:
    """Get user (v2 with additional fields)."""
    user = await repo.get_user(user_id)
    return UserResponseV2.from_orm(user)

app.include_router(v1_router)
app.include_router(v2_router)

✅ Testing FastAPI Apps

from fastapi.testclient import TestClient
import pytest

client = TestClient(app)

def test_create_user() -> None:
    """Test user creation."""
    response = client.post(
        "/api/v1/users/",
        json={
            "name": "Alice",
            "email": "[email protected]",
            "age": 30
        }
    )
    assert response.status_code == 201
    data = response.json()
    assert data["name"] == "Alice"
    assert "id" in data

def test_get_user_not_found() -> None:
    """Test getting non-existent user."""
    response = client.get("/api/v1/users/999")
    assert response.status_code == 404
    assert response.json()["detail"] == "User not found"

@pytest.mark.asyncio
async def test_async_endpoint() -> None:
    """Test async endpoint."""
    response = client.get("/api/v1/users/")
    assert response.status_code == 200
    assert isinstance(response.json(), list)

✅ Authentication and Security

from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

security = HTTPBearer()

async def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    repo: UserRepo = Depends()
) -> User:
    """Get current user from authorization header."""
    token = credentials.credentials
    user = await repo.verify_token(token)
    if user is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
        )
    return user

@app.get("/me")
async def get_me(current_user: User = Depends(get_current_user)) -> UserResponse:
    """Get current user."""
    return UserResponse.from_orm(current_user)

✅ WebSocket Support

from fastapi import WebSocket

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket) -> None:
    """WebSocket endpoint for real-time updates."""
    await websocket.accept()

    try:
        while True:
            data = await websocket.receive_text()
            await websocket.send_text(f"Echo: {data}")
    finally:
        await websocket.close()

✅ Custom Middleware

from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
import time

class TimingMiddleware(BaseHTTPMiddleware):
    """Middleware to time requests."""

    async def dispatch(self, request: Request, call_next):
        """Time the request."""
        start_time = time.time()
        response = await call_next(request)
        process_time = time.time() - start_time
        response.headers["X-Process-Time"] = str(process_time)
        return response

app.add_middleware(TimingMiddleware)

OpenAPI Configuration

✅ Customize OpenAPI Documentation

app = FastAPI(
    title="My API",
    description="A comprehensive API with FastAPI",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc",
)

@app.get("/users/{user_id}", include_in_schema=False)
async def internal_endpoint(user_id: int) -> dict:
    """Internal endpoint (excluded from docs)."""
    return {"internal": True}

Common Pitfalls

❌ Don't Run Blocking Code in Async Endpoints

# BAD: Blocking I/O in async endpoint
@app.get("/heavy")
async def heavy_computation():
    result = blocking_function()  # Blocks event loop
    return {"result": result}

# GOOD: Offload to executor
@app.get("/heavy")
async def heavy_computation():
    loop = asyncio.get_event_loop()
    result = await loop.run_in_executor(None, blocking_function)
    return {"result": result}

❌ Don't Forget Response Models

# BAD: Missing response model (no validation)
@app.get("/users/{user_id}")
async def get_user(user_id: int) -> dict:
    user = await repo.get_user(user_id)
    return {"id": user.id, "name": user.name}

# GOOD: Use response model for validation
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int) -> UserResponse:
    user = await repo.get_user(user_id)
    return UserResponse.from_orm(user)

❌ Don't Mix Sync and Async Database Calls

# BAD: Mixing sync and async
@app.get("/users")
async def get_users():
    users = db.session.query(User).all()  # Sync call in async context
    return users

# GOOD: Use async database
@app.get("/users")
async def get_users(session: DB):
    result = await session.execute(select(User))
    users = result.scalars().all()
    return users

Project Structure

app/
├── __init__.py
├── main.py              # FastAPI app setup
├── dependencies.py      # Dependency injection
├── models/              # Pydantic models
│   ├── __init__.py
│   ├── user.py
│   └── product.py
├── routes/              # API routes
│   ├── __init__.py
│   ├── users.py
│   └── products.py
├── services/            # Business logic
│   ├── __init__.py
│   ├── user_service.py
│   └── product_service.py
├── repositories/        # Database access
│   ├── __init__.py
│   ├── user_repository.py
│   └── product_repository.py
└── utils/               # Utilities
    ├── __init__.py
    ├── security.py
    └── validators.py

References