원클릭으로
fastapi-workflow
FastAPI framework workflow guidelines. Activate when working with FastAPI projects, uvicorn, or FastAPI-specific patterns.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
FastAPI framework workflow guidelines. Activate when working with FastAPI projects, uvicorn, or FastAPI-specific patterns.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Language-agnostic API design patterns covering REST and GraphQL, including resource naming, HTTP methods, status codes, versioning, pagination, filtering, authentication, error handling, and schema design. Activate when working with APIs, REST endpoints, GraphQL schemas, API documentation, OpenAPI/Swagger, JWT, OAuth2, endpoint design, API versioning, rate limiting, or GraphQL resolvers.
Git workflow and commit guidelines. Trigger keywords: git, commit, push, .git, version control. MUST be activated before ANY git commit, push, or version control operation. Includes security scanning for secrets (API keys, tokens, .env files), commit message formatting with HEREDOC, logical commit grouping (docs, test, feat, fix, refactor, chore, build, deps), push behavior rules, safety rules for hooks and force pushes, and CRITICAL safeguards for destructive operations (filter-branch, gc --prune, reset --hard). Activate when user requests committing changes, pushing code, creating commits, rewriting history, or performing any git operations including analyzing uncommitted changes.
Testing workflow patterns and quality standards. Activate when working with tests, test files, test directories, code quality tools, coverage reports, or testing tasks. Includes zero-warnings policy, targeted testing during development, mocking patterns, and best practices across languages.
Ansible automation workflow guidelines. Activate when working with Ansible playbooks, ansible-playbook, inventory files (.yml, .ini), or Ansible-specific patterns.
Claude Code AI-assisted development workflow. Activate when discussing Claude Code usage, AI-assisted coding, prompting strategies, or Claude Code-specific patterns.
Guidelines for containerized projects using Docker, Dockerfile, docker-compose, container, and containerization. Covers multi-stage builds, security, signal handling, entrypoint scripts, and deployment workflows.
| name | fastapi-workflow |
| description | FastAPI framework workflow guidelines. Activate when working with FastAPI projects, uvicorn, or FastAPI-specific patterns. |
| location | user |
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
| Task | Tool | Command |
|---|---|---|
| Run dev | Uvicorn | uvicorn app.main:app --reload |
| Test | pytest + httpx | uv run pytest |
| Docs | Built-in | /docs or /redoc |
| Lint | Ruff | uv run ruff check . |
| Format | Ruff | uv run ruff format . |
| Type check | mypy | uv run mypy . |
project/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI app instance
│ ├── config.py # BaseSettings configuration
│ ├── dependencies.py # Shared Depends() callables
│ ├── exceptions.py # Custom exception handlers
│ ├── middleware.py # Custom middleware
│ ├── models/ # SQLAlchemy/Pydantic models
│ │ ├── __init__.py
│ │ ├── domain.py # SQLAlchemy ORM models
│ │ └── schemas.py # Pydantic schemas
│ ├── routers/ # APIRouter modules
│ │ ├── __init__.py
│ │ ├── users.py
│ │ └── items.py
│ ├── services/ # Business logic layer
│ │ └── __init__.py
│ └── db/ # Database configuration
│ ├── __init__.py
│ └── session.py
├── tests/
│ ├── conftest.py # Fixtures
│ └── test_*.py
├── pyproject.toml
└── .env
Dependencies MUST use Depends() for:
from fastapi import Depends, APIRouter
from sqlalchemy.ext.asyncio import AsyncSession
from app.db.session import get_db
from app.config import Settings, get_settings
router = APIRouter()
# Database session dependency
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with async_session_maker() as session:
yield session
# Settings dependency
def get_settings() -> Settings:
return Settings()
# Service with injected dependencies
class UserService:
def __init__(
self,
db: AsyncSession = Depends(get_db),
settings: Settings = Depends(get_settings),
):
self.db = db
self.settings = settings
# Route using dependency
@router.get("/users/{user_id}")
async def get_user(
user_id: int,
service: UserService = Depends(),
) -> UserResponse:
return await service.get_user(user_id)
Depends(get_db, use_cache=False) to disable caching when neededRequest and response models MUST use Pydantic BaseModel or dataclasses.
from pydantic import BaseModel, Field, EmailStr, ConfigDict
from datetime import datetime
# Request schema
class UserCreate(BaseModel):
email: EmailStr
name: str = Field(..., min_length=1, max_length=100)
age: int = Field(..., ge=0, le=150)
# Response schema with ORM mode
class UserResponse(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
email: EmailStr
name: str
created_at: datetime
# Nested models
class UserWithItems(UserResponse):
items: list[ItemResponse] = []
from_attributes=True for ORM model conversionAll configuration MUST use Pydantic BaseSettings.
from pydantic_settings import BaseSettings, SettingsConfigDict
from functools import lru_cache
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
)
# Database
database_url: str
database_pool_size: int = 5
# API
api_prefix: str = "/api/v1"
debug: bool = False
# Security
secret_key: str
access_token_expire_minutes: int = 30
@lru_cache
def get_settings() -> Settings:
return Settings()
.env files for local development@lru_cache for settings singleton.env valuesDatabase operations MUST be async using SQLAlchemy 2.0+ async.
from sqlalchemy.ext.asyncio import (
AsyncSession,
async_sessionmaker,
create_async_engine,
)
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass
# Engine setup
engine = create_async_engine(
settings.database_url,
echo=settings.debug,
pool_size=settings.database_pool_size,
)
async_session_maker = async_sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False,
)
# Dependency
async def get_db() -> AsyncGenerator[AsyncSession, None]:
async with async_session_maker() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
expire_on_commit=False for async sessionsRouters MUST be organized by domain with clear prefixes and tags.
# app/routers/users.py
from fastapi import APIRouter, Depends, status
router = APIRouter(
prefix="/users",
tags=["users"],
responses={404: {"description": "Not found"}},
)
@router.post("/", status_code=status.HTTP_201_CREATED)
async def create_user(user: UserCreate) -> UserResponse:
...
@router.get("/{user_id}")
async def get_user(user_id: int) -> UserResponse:
...
# app/main.py
from fastapi import FastAPI
from app.routers import users, items
from app.config import get_settings
settings = get_settings()
app = FastAPI(
title="My API",
version="1.0.0",
openapi_url=f"{settings.api_prefix}/openapi.json",
)
app.include_router(users.router, prefix=settings.api_prefix)
app.include_router(items.router, prefix=settings.api_prefix)
fastapi.statusfrom fastapi import FastAPI, Request, HTTPException
from fastapi.responses import JSONResponse
# Custom exception
class NotFoundError(Exception):
def __init__(self, resource: str, id: int):
self.resource = resource
self.id = id
# Exception handler
@app.exception_handler(NotFoundError)
async def not_found_handler(request: Request, exc: NotFoundError) -> JSONResponse:
return JSONResponse(
status_code=404,
content={"detail": f"{exc.resource} with id {exc.id} not found"},
)
# Usage in route
@router.get("/{user_id}")
async def get_user(user_id: int, db: AsyncSession = Depends(get_db)) -> UserResponse:
user = await db.get(User, user_id)
if not user:
raise NotFoundError("User", user_id)
return user
import pytest
from httpx import AsyncClient, ASGITransport
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker
from app.main import app
from app.db.session import get_db
from app.config import get_settings, Settings
# Override settings
def get_settings_override() -> Settings:
return Settings(database_url="sqlite+aiosqlite:///:memory:")
app.dependency_overrides[get_settings] = get_settings_override
@pytest.fixture
async def client():
async with AsyncClient(
transport=ASGITransport(app=app),
base_url="http://test",
) as ac:
yield ac
@pytest.mark.asyncio
async def test_create_user(client: AsyncClient):
response = await client.post(
"/api/v1/users/",
json={"email": "test@example.com", "name": "Test", "age": 25},
)
assert response.status_code == 201
assert response.json()["email"] == "test@example.com"
httpx.AsyncClient for async testsfrom fastapi import BackgroundTasks
async def send_notification(email: str, message: str) -> None:
# Async notification logic
...
@router.post("/users/")
async def create_user(
user: UserCreate,
background_tasks: BackgroundTasks,
) -> UserResponse:
new_user = await create_user_in_db(user)
background_tasks.add_task(send_notification, user.email, "Welcome!")
return new_user
from fastapi import FastAPI, Request
from starlette.middleware.base import BaseHTTPMiddleware
import time
class TimingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
start = time.perf_counter()
response = await call_next(request)
duration = time.perf_counter() - start
response.headers["X-Process-Time"] = str(duration)
return response
app.add_middleware(TimingMiddleware)
# CORS middleware
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=settings.allowed_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
from fastapi import FastAPI
app = FastAPI(
title="My API",
description="API for managing resources",
version="1.0.0",
terms_of_service="https://example.com/terms/",
contact={
"name": "API Support",
"url": "https://example.com/support",
"email": "support@example.com",
},
license_info={
"name": "MIT",
"url": "https://opensource.org/licenses/MIT",
},
)
# Route documentation
@router.get(
"/{user_id}",
summary="Get a user by ID",
description="Retrieve detailed user information by their unique identifier.",
response_description="The user object",
responses={
404: {"description": "User not found"},
422: {"description": "Validation error"},
},
)
async def get_user(user_id: int) -> UserResponse:
"""
Get a user with all their details.
- **user_id**: The unique identifier of the user
"""
...
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db),
) -> User:
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, settings.secret_key, algorithms=["HS256"])
user_id: int = payload.get("sub")
if user_id is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = await db.get(User, user_id)
if user is None:
raise credentials_exception
return user
# Protected route
@router.get("/me")
async def read_users_me(current_user: User = Depends(get_current_user)) -> UserResponse:
return current_user