FastAPI — SKILL.md

Raw skill file that agents receive when using this skill

Download
---
name: "FastAPI"
description: "Skill for FastAPI — auto-generated from documentation"
version: "1.0.0"
author: "skynet"
category: "dev"
agents: ["claude-code", "codex", "gemini"]
tags: ["fastapi", "dev", "auto-generated"]
---

# FastAPI

---
name: FastAPI
description: Use when building high-performance Python web APIs with automatic documentation, type hints, and async support. Essential for REST APIs, microservices, and data validation.
category: dev
metadata:
  author: skynet
  version: 1.0.0
---

# FastAPI

## Installation

```bash
# Basic installation
pip install fastapi uvicorn

# With all optional dependencies
pip install "fastapi[all]"

# For production
pip install fastapi uvicorn[standard] gunicorn
```

## Quick Start

```python
# main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}
```

```bash
# Development server
uvicorn main:app --reload

# Production server
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
```

## Pydantic Models & Validation

```python
from pydantic import BaseModel, EmailStr, validator
from datetime import datetime
from typing import Optional, List

class UserBase(BaseModel):
    email: EmailStr
    name: str
    age: Optional[int] = None

class UserCreate(UserBase):
    password: str
    
    @validator('password')
    def validate_password(cls, v):
        if len(v) < 8:
            raise ValueError('Password must be at least 8 characters')
        return v

class UserResponse(UserBase):
    id: int
    created_at: datetime
    
    class Config:
        orm_mode = True

@app.post("/users/", response_model=UserResponse)
def create_user(user: UserCreate):
    # Process user creation
    return user
```

## Path & Query Parameters

```python
from enum import Enum
from typing import Optional, List

class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"

@app.get("/models/{model_name}")
def get_model(model_name: ModelName):
    return {"model_name": model_name}

@app.get("/items/")
def read_items(
    skip: int = 0,
    limit: int = 100,
    tags: List[str] = Query(None, description="Tags to filter by"),
    q: Optional[str] = Query(None, min_length=3, max_length=50)
):
    return {"skip": skip, "limit": limit, "tags": tags, "q": q}
```

## Request Body & Forms

```python
from fastapi import Form, File, UploadFile

# JSON body
@app.post("/items/")
def create_item(item: Item):
    return item

# Form data
@app.post("/login/")
def login(username: str = Form(), password: str = Form()):
    return {"username": username}

# File upload
@app.post("/files/")
def upload_file(file: UploadFile = File(...)):
    return {"filename": file.filename, "size": file.size}

# Multiple files
@app.post("/uploadfiles/")
def upload_files(files: List[UploadFile] = File(...)):
    return [{"filename": f.filename} for f in files]
```

## Dependency Injection

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

security = HTTPBearer()

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

def get_current_user(
    credentials: HTTPAuthorizationCredentials = Depends(security),
    db: Session = Depends(get_db)
):
    token = credentials.credentials
    user = verify_token(token, db)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials"
        )
    return user

@app.get("/protected/")
def protected_route(current_user: User = Depends(get_current_user)):
    return {"user": current_user}
```

## Middleware & CORS

```python
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
import time

# CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Custom middleware
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    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
```

## Error Handling

```python
from fastapi import HTTPException
from fastapi.responses import JSONResponse

class CustomException(Exception):
    def __init__(self, name: str):
        self.name = name

@app.exception_handler(CustomException)
def custom_exception_handler(request: Request, exc: CustomException):
    return JSONResponse(
        status_code=418,
        content={"message": f"Oops! {exc.name} did something wrong."}
    )

@app.get("/items/{item_id}")
def read_item(item_id: int):
    if item_id == 0:
        raise HTTPException(
            status_code=404,
            detail="Item not found",
            headers={"X-Error": "Custom error header"}
        )
    return {"item_id": item_id}
```

## Async Operations

```python
import asyncio
import httpx

@app.get("/async-data")
async def get_async_data():
    async with httpx.AsyncClient() as client:
        response = await client.get("https://api.example.com/data")
        return response.json()

@app.post("/process-async/")
async def process_async(data: ProcessData):
    # Simulate async processing
    await asyncio.sleep(1)
    result = await process_data_async(data)
    return {"result": result, "processed_at": datetime.utcnow()}
```

## Database Integration (SQLAlchemy)

```python
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, Session

# Database setup
SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/dbname"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()

# Models
class User(Base):
    __tablename__ = "users"
    
    id = Column(Integer, primary_key=True, index=True)
    email = Column(String, unique=True, index=True)
    name = Column(String)

# Database operations
@app.get("/users/{user_id}", response_model=UserResponse)
def get_user(user_id: int, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.id == user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user
```

## Testing

```python
# test_main.py
from fastapi.testclient import TestClient
import pytest

client = TestClient(app)

def test_read_main():
    response = client.get("/")
    assert response.status_code == 200
    assert response.json() == {"Hello": "World"}

def test_create_user():
    user_data = {
        "email": "test@example.com",
        "name": "Test User",
        "password": "testpassword123"
    }
    response = client.post("/users/", json=user_data)
    assert response.status_code == 200
    assert response.json()["email"] == user_data["email"]

# Run tests
pytest test_main.py -v
```

## Decision Tree

```
Choose FastAPI approach:
├── Simple CRUD API? → Use Pydantic models + SQLAlchemy
├── High-performance async? → Use async/await with asyncio
├── File uploads? → Use UploadFile with Form data
├── Authentication needed?
│   ├── Simple token? → Use HTTPBearer dependency
│   └── OAuth2/JWT? → Use FastAPI security utilities
├── External API calls? → Use httpx with async client
└── Real-time features? → Consider WebSocket support
```

## Deployment Commands

```bash
# Docker
echo "FROM python:3.9
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD uvicorn main:app --host 0.0.0.0 --port 8000" > Dockerfile

docker build -t my-api .
docker run -p 8000:8000 my-api

# Gunicorn for production
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker

# Environment variables
export DATABASE_URL="postgresql://user:pass@localhost/db"
export SECRET_KEY="your-secret-key"
uvicorn main:app --env-file .env
```

## Troubleshooting

**Error: `422 Unprocessable Entity`**
```
Fix: Check Pydantic model validation
- Verify required fields are present
- Check data types match model definition
- Add proper validators for custom validation
```

**Error: `ImportError: No module named 'email_validator'`**
```bash
pip install email-validator
```

**Error: `RuntimeError: cannot be called from a running async loop`**
```python
# Wrong
response = requests.get(url)

# Right
async with httpx.AsyncClient() as client:
    response = await client.get(url)
```

**Error: `sqlalchemy.exc.OperationalError: connection failed`**
```python
# Check database URL and ensure DB is running
SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost:5432/dbname"

# Test connection
from sqlalchemy import create_engine
engine = create_engine(SQLALCHEMY_DATABASE_URL)
engine.connect()
```

curl -s https://skills.skynet.ceo/api/skills/fastapi/skill.md