Fastapi Patterns
Scannednpx machina-cli add skill ruslan-korneev/python-backend-claude-plugins/fastapi-patterns --openclawFastAPI Patterns
Best practices and patterns for FastAPI projects with SQLAlchemy 2.0 and dependency-injector.
Triggers
Use this skill when the user:
- Creates a new FastAPI project or module
- Asks about FastAPI application structure
- Works with SQLAlchemy models and repositories
- Configures Dependency Injection
- Creates DTOs (Pydantic models)
Layer Architecture
Router → Service → Repository → Database
↓ ↓ ↓
DTO DTO Model/DTO
- Router — HTTP endpoints, request validation
- Service — business logic, orchestration
- Repository — database operations, CRUD operations
Modular Structure
src/
├── core/
│ ├── config.py # Settings (pydantic-settings)
│ ├── database.py # Engine, Base, session
│ ├── container.py # DI Container
│ ├── dependencies.py # FastAPI dependencies
│ ├── exceptions.py # Custom exceptions
│ └── repositories.py # BaseRepository
├── modules/
│ ├── users/
│ │ ├── __init__.py
│ │ ├── models.py
│ │ ├── dto.py
│ │ ├── repositories.py
│ │ ├── services.py
│ │ └── routers.py
│ └── orders/
│ └── ...
└── main.py
BaseRepository with Generics
More details: ${CLAUDE_PLUGIN_ROOT}/skills/fastapi-patterns/references/repository.md
from typing import Generic, TypeVar
from collections.abc import Sequence
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
ModelT = TypeVar("ModelT")
CreateDTOT = TypeVar("CreateDTOT")
ReadDTOT = TypeVar("ReadDTOT")
class BaseRepository(Generic[ModelT, CreateDTOT, ReadDTOT]):
"""Base repository with generic CRUD operations."""
def __init__(self, session: AsyncSession, model: type[ModelT]) -> None:
self._session = session
self._model = model
async def get_all(self) -> Sequence[ReadDTOT]:
result = await self._session.execute(select(self._model))
return result.scalars().all()
async def save(self, data: ModelT | CreateDTOT) -> ReadDTOT:
if isinstance(data, self._model):
entity = data
else:
entity = self._model(**data.model_dump())
self._session.add(entity)
await self._session.flush()
return entity
DTOs with Pydantic v2
More details: ${CLAUDE_PLUGIN_ROOT}/skills/fastapi-patterns/references/dto.md
from pydantic import BaseModel, ConfigDict
class BaseDTO(BaseModel):
"""Base DTO with ORM mode."""
model_config = ConfigDict(
from_attributes=True,
populate_by_name=True,
str_strip_whitespace=True,
)
class UserCreateDTO(BaseDTO):
email: str
name: str
class UserReadDTO(BaseDTO):
id: int
email: str
name: str
Dependency Injection
More details: ${CLAUDE_PLUGIN_ROOT}/skills/fastapi-patterns/references/di.md
# container.py
from dependency_injector import containers, providers
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
session_maker = providers.Singleton(
async_sessionmaker,
bind=engine,
)
user_repository = providers.Factory(
UserRepository,
session=session_maker,
)
user_service = providers.Factory(
UserService,
repository=user_repository,
)
# routers.py
from dependency_injector.wiring import inject, Provide
@router.get("/users/{id}")
@inject
async def get_user(
id: int,
service: Annotated[UserService, Depends(Provide[Container.user_service])],
) -> UserReadDTO:
return await service.get_by_id(id)
Exception Handling
More details: ${CLAUDE_PLUGIN_ROOT}/skills/fastapi-patterns/references/exceptions.md
# exceptions.py
class AppError(Exception):
"""Base application error."""
status_code: int = 500
detail: str = "Internal server error"
def __init__(self, detail: str | None = None) -> None:
self.detail = detail or self.detail
class NotFoundError(AppError):
status_code = 404
detail = "Resource not found"
class ConflictError(AppError):
status_code = 409
detail = "Resource already exists"
# handlers.py
async def app_exception_handler(request: Request, exc: AppError) -> JSONResponse:
return JSONResponse(
status_code=exc.status_code,
content={"detail": exc.detail},
)
# main.py
app.add_exception_handler(AppError, app_exception_handler)
Transaction Management
# Via session_maker context manager
async def create_order(self, data: OrderCreateDTO) -> OrderReadDTO:
async with self._session_maker() as session:
order = Order(**data.model_dump())
session.add(order)
await session.commit()
return OrderReadDTO.model_validate(order)
# Or via repository
async def create_with_items(self, data: OrderCreateDTO) -> OrderReadDTO:
order = await self._order_repo.save(data)
for item in data.items:
await self._item_repo.save(OrderItem(order_id=order.id, **item))
await self._session.commit()
return order
Plugin Commands
/fastapi:module <name>— create a complete module/fastapi:endpoint <method> <path> <module>— create an endpoint/fastapi:dto <model>— create DTOs from model
Source
git clone https://github.com/ruslan-korneev/python-backend-claude-plugins/blob/master/plugins/fastapi/skills/fastapi-patterns/SKILL.mdView on GitHub Overview
Provides best practices and patterns for FastAPI projects that use SQLAlchemy 2.0 and dependency-injector. It outlines a layered Router → Service → Repository → Database architecture, DTO-driven data exchange with Pydantic v2, and a modular structure driven by a DI container.
How This Skill Works
The pattern enforces a clean separation of concerns: DTOs map data between layers, a generic BaseRepository handles CRUD with SQLAlchemy, and services orchestrate business logic. Routers validate HTTP requests and delegate to services, while a Dependency Injection container wires dependencies and config.
When to Use It
- When starting a new FastAPI project or module
- When you need clear application structure guidance
- When modeling with SQLAlchemy models and repositories
- When configuring dependency injection across layers
- When designing DTOs with Pydantic models
Quick Start
- Step 1: Create a modular FastAPI project structure (core, modules, main.py)
- Step 2: Implement DTOs with Pydantic v2 and a BaseRepository
- Step 3: Configure and wire the DI container, then run the app
Best Practices
- Enforce Router → Service → Repository → Database layering
- Use a generic BaseRepository to standardize CRUD across models
- Define DTOs with Pydantic v2 and ORM-compatible Config
- Centralize configuration and DI in a dedicated container
- Handle errors with consistent exception classes and mapping
Example Use Cases
- A users module with models.py, dto.py, repositories.py, services.py, routers.py
- A shared BaseRepository used by multiple modules for CRUD
- DI Container with session_maker and providers for repositories and services
- Routers.py using dependency injection to obtain services
- Main.py wiring and application initialization