fastapi-endpoint-patterns
Conventions for writing FastAPI endpoints with proper typing, status codes, and error handling
소스 정보
- 저장소
- ag2ai/resource-hub
- 최근 소스 활동
- 2026년 3월 19일 04:42
- 감지된 SKILL.md 언어
- 영어
- 스타
- 4
- 포크
- 3
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
SKILL.md 표시 중
SKILL.md
소스 지침 · 읽기 전용 미리보기- name
- fastapi-endpoint-patterns
- description
- Conventions for writing FastAPI endpoints with proper typing, status codes, and error handling
- license
- Apache-2.0
# Endpoint Patterns
## Basic Endpoint Structure
Always use `async def`. Specify `response_model` and `status_code`.
```python
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.deps.database import get_db
from app.schemas.user import UserCreate, UserRead
from app.services import user_service
router = APIRouter()
@router.post("/", response_model=UserRead, status_code=status.HTTP_201_CREATED)
async def create_user(
payload: UserCreate,
db: AsyncSession = Depends(get_db),
) -> UserRead:
user = await user_service.create_user(db, payload)
return user
```
## Response Models
Define separate schemas for create, read, and update operations:
```python
from pydantic import BaseModel, ConfigDict
class UserBase(BaseModel):
email: str
name: str
class UserCreate(UserBase):
password: str
class UserUpdate(BaseModel):
email: str | None = None
name: str | None = None
class UserRead(UserBase):
id: int
model_config = ConfigDict(from_attributes=True)
```
- `UserCreate` -- what the client sends to create a resource.
- `UserUpdate` -- partial update; all fields optional.
- `UserRead` -- what the API returns. Includes `id`, excludes `password`.
## Status Codes
Use explicit status codes from `fastapi.status`:
| Operation | Status Code | Constant |
|-----------|------------|----------|
| Create | 201 | `HTTP_201_CREATED` |
| Read | 200 | `HTTP_200_OK` (default) |
| Update | 200 | `HTTP_200_OK` |
| Delete | 204 | `HTTP_204_NO_CONTENT` |
For 204 responses, set `response_model=None`:
```python
@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT, response_model=None)
async def delete_user(user_id: int, db: AsyncSession = Depends(get_db)):
await user_service.delete_user(db, user_id)
```
## Dependency Injection
Inject shared resources with `Depends()`:
```python
from fastapi import Depends
from app.deps.auth import get_current_user
from app.deps.database import get_db
@router.get("/me", response_model=UserRead)
async def get_me(
current_user: UserRead = Depends(get_current_user),
) -> UserRead:
return current_user
```
Chain dependencies for layered auth:
```python
# app/deps/auth.py
async def get_current_user(token: str = Depends(oauth2_scheme), db=Depends(get_db)):
user = await verify_token(token, db)
if not user:
raise HTTPException(status_code=401, detail="Invalid token")
return user
async def require_admin(user=Depends(get_current_user)):
if not user.is_admin:
raise HTTPException(status_code=403, detail="Admin required")
return user
```
## Error Handling
Raise `HTTPException` for expected errors:
```python
@router.get("/{user_id}", response_model=UserRead)
async def get_user(user_id: int, db: AsyncSession = Depends(get_db)) -> UserRead:
user = await user_service.get_user_by_id(db, user_id)
if not user:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"User {user_id} not found",
)
return user
```
Use exception handlers for global error formatting:
```python
# app/main.py
from fastapi.responses import JSONResponse
@app.exception_handler(ValueError)
async def value_error_handler(request, exc):
return JSONResponse(status_code=400, content={"detail": str(exc)})
```
## Path and Query Parameters
```python
@router.get("/", response_model=list[UserRead])
async def list_users(
skip: int = 0,
limit: int = 100,
search: str | None = None,
db: AsyncSession = Depends(get_db),
) -> list[UserRead]:
return await user_service.list_users(db, skip=skip, limit=limit, search=search)
```
Use `Path()` and `Query()` for validation:
```python
from fastapi import Path, Query
@router.get("/{user_id}")
async def get_user(
user_id: int = Path(..., gt=0, description="The user ID"),
fields: list[str] = Query(default=[], description="Fields to include"),
):
...
```
GitHub에서 보기