home / skills / personamanagmentlayer / pcl / fastapi-expert
This skill guides building high-performance FastAPI APIs with type safety, async support, and robust authentication and documentation.
npx playbooks add skill personamanagmentlayer/pcl --skill fastapi-expertReview the files below or copy the command above to add this skill to your agents.
---
name: fastapi-expert
version: 1.0.0
description: Expert-level FastAPI development for high-performance Python APIs with async support
category: api
tags: [fastapi, python, api, async, rest, openapi, pydantic]
allowed-tools:
- Read
- Write
- Edit
- Bash(python:*, pip:*, uvicorn:*)
---
# FastAPI Expert
Expert guidance for FastAPI - modern, fast Python web framework for building APIs with automatic OpenAPI documentation and type safety.
## Core Concepts
### FastAPI Features
- Fast performance (Starlette + Pydantic)
- Automatic OpenAPI/Swagger docs
- Type hints and validation
- Async/await support
- Dependency injection
- OAuth2 and JWT
- WebSocket support
### Key Components
- Path operations (routes)
- Request/response models (Pydantic)
- Dependency injection
- Middleware
- Background tasks
- Testing with TestClient
## Basic FastAPI Application
```python
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel, EmailStr, Field
from typing import List, Optional
import uvicorn
app = FastAPI(
title="My API",
description="Production-ready FastAPI",
version="1.0.0"
)
# Models
class UserCreate(BaseModel):
email: EmailStr
name: str = Field(..., min_length=2, max_length=100)
age: Optional[int] = Field(None, ge=0, le=150)
class UserResponse(BaseModel):
id: int
email: str
name: str
class Config:
from_attributes = True
# Routes
@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
# Create user in database
db_user = await db.users.create(**user.dict())
return db_user
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
user = await db.users.get(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
@app.get("/users", response_model=List[UserResponse])
async def list_users(skip: int = 0, limit: int = 100):
return await db.users.find_many(skip=skip, limit=limit)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
```
## Dependency Injection
```python
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.ext.asyncio import AsyncSession
# Database dependency
async def get_db() -> AsyncSession:
async with async_session() as session:
yield session
# Auth dependency
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db)
):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials"
)
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
user_id: int = payload.get("sub")
if user_id is None:
raise credentials_exception
user = await db.get(User, user_id)
if user is None:
raise credentials_exception
return user
# Use dependencies
@app.get("/me", response_model=UserResponse)
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user
@app.post("/posts")
async def create_post(
post: PostCreate,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db)
):
db_post = Post(**post.dict(), user_id=current_user.id)
db.add(db_post)
await db.commit()
return db_post
```
## Authentication
```python
from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def verify_password(plain_password: str, hashed_password: str) -> bool:
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password: str) -> str:
return pwd_context.hash(password)
def create_access_token(data: dict, expires_delta: timedelta = None):
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15))
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
@app.post("/token")
async def login(
form_data: OAuth2PasswordRequestForm = Depends(),
db: AsyncSession = Depends(get_db)
):
user = await authenticate_user(db, form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=401, detail="Invalid credentials")
access_token = create_access_token(data={"sub": str(user.id)})
return {"access_token": access_token, "token_type": "bearer"}
```
## Database Integration (SQLAlchemy)
```python
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy import Column, Integer, String, Boolean
DATABASE_URL = "postgresql+asyncpg://user:password@localhost/dbname"
engine = create_async_engine(DATABASE_URL, echo=True)
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True, nullable=False)
hashed_password = Column(String, nullable=False)
is_active = Column(Boolean, default=True)
# CRUD operations
async def get_user(db: AsyncSession, user_id: int):
return await db.get(User, user_id)
async def create_user(db: AsyncSession, user: UserCreate):
hashed_password = get_password_hash(user.password)
db_user = User(email=user.email, hashed_password=hashed_password)
db.add(db_user)
await db.commit()
await db.refresh(db_user)
return db_user
```
## Request Validation
```python
from pydantic import BaseModel, validator, root_validator
from typing import Optional
from datetime import date
class PostCreate(BaseModel):
title: str = Field(..., min_length=5, max_length=200)
content: str = Field(..., min_length=10)
published: bool = False
tags: List[str] = Field(default_factory=list, max_items=10)
@validator('tags')
def validate_tags(cls, v):
return [tag.lower().strip() for tag in v]
@validator('title')
def validate_title(cls, v):
if any(word in v.lower() for word in ['spam', 'xxx']):
raise ValueError('Invalid content')
return v
```
## Background Tasks
```python
from fastapi import BackgroundTasks
def send_email(email: str, message: str):
# Send email
print(f"Sending email to {email}: {message}")
@app.post("/send-notification")
async def send_notification(
email: str,
background_tasks: BackgroundTasks
):
background_tasks.add_task(send_email, email, "Welcome!")
return {"message": "Notification sent"}
```
## Testing
```python
from fastapi.testclient import TestClient
import pytest
client = TestClient(app)
def test_create_user():
response = client.post(
"/users",
json={"email": "[email protected]", "name": "Test User"}
)
assert response.status_code == 201
assert response.json()["email"] == "[email protected]"
def test_get_user():
response = client.get("/users/1")
assert response.status_code == 200
assert "email" in response.json()
@pytest.mark.asyncio
async def test_async_endpoint():
async with AsyncClient(app=app, base_url="http://test") as ac:
response = await ac.get("/users")
assert response.status_code == 200
```
## Best Practices
- Use Pydantic models for validation
- Implement proper error handling
- Use dependency injection
- Add rate limiting
- Enable CORS properly
- Use async/await for I/O
- Document with docstrings
- Add proper logging
## Resources
- FastAPI Docs: https://fastapi.tiangolo.com/
- Pydantic: https://docs.pydantic.dev/
- Starlette: https://www.starlette.io/
This skill provides expert-level FastAPI development guidance for building high-performance, production-ready Python APIs with full async support. It focuses on practical patterns for routing, validation, auth, database integration, background tasks, and automated docs. The goal is to accelerate safe, maintainable API delivery with modern best practices.
It inspects common FastAPI components and patterns and recommends concrete implementations: Pydantic models for validation, async SQLAlchemy sessions for database access, OAuth2/JWT flows for authentication, dependency injection for reusable logic, and background tasks for non-blocking work. The skill highlights testing strategies, request/response modeling, middleware, and OpenAPI documentation to ensure reliable, observable APIs.
Should I use Pydantic models for both requests and responses?
Yes. Use Pydantic models for request validation and response serialization to ensure type safety, automatic docs, and consistent shapes across your API.
How do I handle authentication securely?
Use OAuth2 with JWT for stateless auth, validate tokens in a dependency that checks the DB and token claims, and rotate secrets and expirations appropriately.