Help us improve
Share bugs, ideas, or general feedback.
From fastapi
Best practices and patterns for FastAPI projects with SQLAlchemy 2.0 and dependency-injector.
npx claudepluginhub ruslan-korneev/claude-plugins --plugin fastapiHow this skill is triggered — by the user, by Claude, or both
Slash command
/fastapi:fastapi-patternsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Best practices and patterns for FastAPI projects with SQLAlchemy 2.0 and dependency-injector.
Provides FastAPI best practices for project structure, Pydantic v2 schemas, dependency injection, async handlers, auth, transactional service layers, and testing with httpx and pytest.
Generates production-ready FastAPI project structures with async patterns, dependency injection, middleware, error handling, and best practices for high-performance APIs.
Provides FastAPI best practices including Pydantic models, SQLAlchemy ORM, async patterns, dependency injection, and JWT authentication for production Python APIs.
Share bugs, ideas, or general feedback.
Best practices and patterns for FastAPI projects with SQLAlchemy 2.0 and dependency-injector.
Use this skill when the user:
Router → Service → Repository → Database
↓ ↓ ↓
DTO DTO Model/DTO
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
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
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
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)
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)
# 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
/fastapi:module <name> — create a complete module/fastapi:endpoint <method> <path> <module> — create an endpoint/fastapi:dto <model> — create DTOs from model