home / skills / doanchienthangdev / omgkit / fastapi

This skill helps you build high-performance FastAPI REST APIs with async patterns, Pydantic v2, dependency injection, and async database integration.

npx playbooks add skill doanchienthangdev/omgkit --skill fastapi

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
4.7 KB
---
name: building-fastapi-apis
description: Builds high-performance FastAPI applications with async/await, Pydantic v2, dependency injection, and SQLAlchemy. Use when creating Python REST APIs, async backends, or microservices.
---

# FastAPI

## Quick Start

```python
from fastapi import FastAPI

app = FastAPI()

@app.get("/health")
async def health_check():
    return {"status": "ok"}

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    return {"user_id": user_id}
```

## Features

| Feature | Description | Guide |
|---------|-------------|-------|
| Routing | Path params, query params, body | [ROUTING.md](ROUTING.md) |
| Pydantic | Schemas, validation, serialization | [SCHEMAS.md](SCHEMAS.md) |
| Dependencies | Injection, database sessions | [DEPENDENCIES.md](DEPENDENCIES.md) |
| Auth | JWT, OAuth2, security utils | [AUTH.md](AUTH.md) |
| Database | SQLAlchemy async, migrations | [DATABASE.md](DATABASE.md) |
| Testing | pytest, AsyncClient | [TESTING.md](TESTING.md) |

## Common Patterns

### Pydantic Schemas

```python
from pydantic import BaseModel, EmailStr, Field, field_validator

class UserCreate(BaseModel):
    email: EmailStr
    name: str = Field(..., min_length=2, max_length=100)
    password: str = Field(..., min_length=8)

    @field_validator("password")
    @classmethod
    def validate_password(cls, v: str) -> str:
        if not any(c.isupper() for c in v):
            raise ValueError("Must contain uppercase")
        if not any(c.isdigit() for c in v):
            raise ValueError("Must contain digit")
        return v

class UserResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: UUID
    email: EmailStr
    name: str
    created_at: datetime
```

### Dependency Injection

```python
from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession

async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with async_session_maker() as session:
        yield session

async def get_current_user(
    token: str = Depends(oauth2_scheme),
    db: AsyncSession = Depends(get_db),
) -> User:
    payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    user = await db.get(User, payload["sub"])
    if not user:
        raise HTTPException(status_code=401)
    return user

# Type aliases for cleaner signatures
DB = Annotated[AsyncSession, Depends(get_db)]
CurrentUser = Annotated[User, Depends(get_current_user)]
```

### Route with Service Layer

```python
@router.get("/", response_model=PaginatedResponse[UserResponse])
async def list_users(
    db: DB,
    current_user: CurrentUser,
    page: int = Query(1, ge=1),
    limit: int = Query(20, ge=1, le=100),
):
    service = UserService(db)
    users, total = await service.list(offset=(page - 1) * limit, limit=limit)
    return PaginatedResponse.create(data=users, total=total, page=page, limit=limit)

@router.post("/", response_model=UserResponse, status_code=201)
async def create_user(db: DB, user_in: UserCreate):
    service = UserService(db)
    if await service.get_by_email(user_in.email):
        raise HTTPException(status_code=409, detail="Email exists")
    return await service.create(user_in)
```

## Workflows

### API Development

1. Define Pydantic schemas for request/response
2. Create service layer for business logic
3. Add route with dependency injection
4. Write tests with pytest-asyncio
5. Document with OpenAPI (automatic)

### Service Pattern

```python
class UserService:
    def __init__(self, db: AsyncSession):
        self.db = db

    async def get_by_id(self, user_id: UUID) -> User | None:
        result = await self.db.execute(
            select(User).where(User.id == user_id)
        )
        return result.scalar_one_or_none()

    async def create(self, data: UserCreate) -> User:
        user = User(**data.model_dump(), hashed_password=hash_password(data.password))
        self.db.add(user)
        await self.db.commit()
        return user
```

## Best Practices

| Do | Avoid |
|----|-------|
| Use async/await everywhere | Sync operations in async code |
| Validate with Pydantic v2 | Manual validation |
| Use dependency injection | Direct imports |
| Handle errors with HTTPException | Generic exceptions |
| Use type hints | `Any` types |

## Project Structure

```
app/
├── main.py
├── core/
│   ├── config.py
│   ├── security.py
│   └── deps.py
├── api/
│   └── v1/
│       ├── __init__.py
│       ├── users.py
│       └── auth.py
├── models/
├── schemas/
├── services/
└── db/
    ├── base.py
    └── session.py
tests/
├── conftest.py
└── test_users.py
```

For detailed examples and patterns, see reference files above.

Overview

This skill builds high-performance FastAPI applications using async/await, Pydantic v2, dependency injection, and SQLAlchemy. It provides patterns and practical examples for creating REST APIs, async backends, and microservices with clear project structure and testing workflows. The focus is on maintainable service layers, type-safe schemas, and scalable routing.

How this skill works

It inspects common API patterns and supplies code examples for async routes, Pydantic v2 schemas, dependency providers, and async SQLAlchemy interactions. The skill highlights service-layer design, dependency annotations, and testable route handlers so you can assemble a robust FastAPI app quickly. It also outlines best practices for validation, error handling, and project layout.

When to use it

  • Building REST APIs or microservices in Python with async requirements
  • Creating type-safe request/response models with Pydantic v2
  • Implementing database access using async SQLAlchemy and dependency injection
  • Designing a service layer for business logic and reusability
  • Setting up testable endpoints with pytest-asyncio and AsyncClient

Best practices

  • Use async/await throughout to avoid blocking the event loop
  • Validate input/output with Pydantic v2 and model_config for serialization
  • Expose DB sessions and auth via dependency injection, not global imports
  • Keep business logic in service classes to simplify routes and tests
  • Raise HTTPException for client errors and return typed response_models

Example use cases

  • User management API: create, list, and authenticate users with JWT and Pydantic validation
  • Paginated resources: routes returning PaginatedResponse with query params and limits
  • Protected endpoints: get_current_user dependency decoding JWT and loading user from DB
  • CRUD services: UserService with async create, get_by_id, and list methods calling SQLAlchemy
  • Automated API docs: endpoints documented by FastAPI/OpenAPI from schemas and response_models

FAQ

Should I mix synchronous code with async FastAPI routes?

Avoid long-running synchronous operations inside async routes. If you must call sync code, run it in a threadpool to prevent blocking the event loop.

How do I validate complex fields like passwords or emails?

Use Pydantic v2 validators (field_validator) and specialized types like EmailStr. Encapsulate validation logic in schema validators to keep routes simple.

Where should I put transactions and commits?

Perform commits inside service methods that own the DB operations. Use dependency-provided AsyncSession and commit after successful writes to keep routes focused on HTTP concerns.