REST API design and implementation patterns for FastAPI endpoints including CRUD operations, pagination, filtering, error handling, and request/response models. Use when building FastAPI endpoints, creating REST APIs, implementing CRUD operations, adding pagination, designing API routes, handling API errors, or when user mentions FastAPI patterns, REST API design, endpoint structure, API best practices, or HTTP endpoints.
Limited to specific tools
Additional assets for this skill
This skill is limited to using the following tools:
README.mdexamples/chat_api.pyexamples/memory_endpoints.pyexamples/user_management.pyscripts/generate-openapi-docs.shscripts/validate-endpoints.shtemplates/crud_endpoint.pytemplates/error_handling.pytemplates/pagination.pyThis skill provides comprehensive REST API design patterns and implementation templates for FastAPI applications. It covers CRUD operations, pagination, filtering, request/response models, error handling, and API organization following modern best practices.
Create, Read, Update, Delete endpoints using FastAPI routers:
# Use CRUD template to generate complete endpoint set
cp ./skills/fastapi-api-patterns/templates/crud_endpoint.py app/routers/items.py
# Customize for your model
# - Replace Item model with your Pydantic model
# - Update database operations
# - Add authentication dependencies
What This Provides:
POST /items/ - Create new itemGET /items/{item_id} - Read single item by IDGET /items/ - Read multiple items with paginationPUT /items/{item_id} - Update entire itemPATCH /items/{item_id} - Partial updateDELETE /items/{item_id} - Delete itemRouter Structure:
from fastapi import APIRouter, HTTPException, Depends, status
from typing import List
router = APIRouter(
prefix="/items",
tags=["items"],
responses={404: {"description": "Not found"}},
)
Implement pagination with query parameters:
# Use pagination template
cp ./skills/fastapi-api-patterns/templates/pagination.py app/utils/pagination.py
Pagination Strategies:
1. Offset-Based Pagination (Simple):
@router.get("/items/")
async def list_items(skip: int = 0, limit: int = 10):
return items[skip : skip + limit]
2. Cursor-Based Pagination (Performance):
@router.get("/items/")
async def list_items(cursor: str | None = None, limit: int = 10):
# Use last item ID as cursor for next page
# Better for large datasets
3. Page-Based Pagination (User-Friendly):
@router.get("/items/")
async def list_items(page: int = 1, page_size: int = 10):
skip = (page - 1) * page_size
return items[skip : skip + page_size]
Filtering Patterns:
@router.get("/items/")
async def list_items(
skip: int = 0,
limit: int = 10,
category: str | None = None,
min_price: float | None = None,
max_price: float | None = None,
search: str | None = None,
):
# Apply filters before pagination
filtered_items = apply_filters(items, category, min_price, max_price, search)
return filtered_items[skip : skip + limit]
Sorting:
from enum import Enum
class SortBy(str, Enum):
name = "name"
price = "price"
created_at = "created_at"
@router.get("/items/")
async def list_items(
sort_by: SortBy = SortBy.created_at,
order: Literal["asc", "desc"] = "desc",
):
# Sort before returning
Define clear Pydantic models for type safety and validation:
Base Models:
from pydantic import BaseModel, Field, validator
from datetime import datetime
class ItemBase(BaseModel):
"""Shared properties"""
name: str = Field(..., min_length=1, max_length=100)
description: str | None = Field(None, max_length=500)
price: float = Field(..., gt=0)
category: str
class ItemCreate(ItemBase):
"""Properties required for creation"""
pass
class ItemUpdate(BaseModel):
"""Properties that can be updated"""
name: str | None = None
description: str | None = None
price: float | None = Field(None, gt=0)
category: str | None = None
class ItemInDB(ItemBase):
"""Properties stored in database"""
id: int
created_at: datetime
updated_at: datetime
class Item(ItemInDB):
"""Properties returned to client"""
class Config:
from_attributes = True
Response Models with Metadata:
from typing import Generic, TypeVar, List
from pydantic import BaseModel
T = TypeVar('T')
class PaginatedResponse(BaseModel, Generic[T]):
items: List[T]
total: int
page: int
page_size: int
pages: int
@router.get("/items/", response_model=PaginatedResponse[Item])
async def list_items(page: int = 1, page_size: int = 10):
total = len(items)
pages = (total + page_size - 1) // page_size
skip = (page - 1) * page_size
return PaginatedResponse(
items=items[skip : skip + page_size],
total=total,
page=page,
page_size=page_size,
pages=pages,
)
Implement consistent error handling:
# Use error handling template
cp ./skills/fastapi-api-patterns/templates/error_handling.py app/utils/errors.py
HTTP Exception Patterns:
from fastapi import HTTPException, status
# 404 Not Found
if item is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Item with id {item_id} not found"
)
# 400 Bad Request
if price < 0:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Price must be positive"
)
# 409 Conflict
if item_exists:
raise HTTPException(
status_code=status.HTTP_409_CONFLICT,
detail="Item with this name already exists"
)
# 403 Forbidden
if not is_owner:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Not authorized to modify this item"
)
Custom Exception Handlers:
from fastapi import Request
from fastapi.responses import JSONResponse
class ItemNotFoundError(Exception):
def __init__(self, item_id: int):
self.item_id = item_id
@app.exception_handler(ItemNotFoundError)
async def item_not_found_handler(request: Request, exc: ItemNotFoundError):
return JSONResponse(
status_code=404,
content={
"error": "not_found",
"message": f"Item {exc.item_id} not found",
"item_id": exc.item_id
}
)
Validation Error Customization:
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
return JSONResponse(
status_code=422,
content={
"error": "validation_error",
"message": "Invalid request data",
"details": exc.errors()
}
)
Use dependencies for authentication, database sessions, and validation:
from fastapi import Depends, Header, HTTPException
# Authentication dependency
async def verify_token(x_token: str = Header(...)):
if x_token != "secret-token":
raise HTTPException(status_code=401, detail="Invalid token")
return x_token
# Database session dependency
async def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# Pagination dependency
async def pagination_params(
skip: int = 0,
limit: int = 10,
max_limit: int = 100
):
if limit > max_limit:
limit = max_limit
return {"skip": skip, "limit": limit}
# Use in endpoints
@router.get("/items/")
async def list_items(
token: str = Depends(verify_token),
db: Session = Depends(get_db),
pagination: dict = Depends(pagination_params),
):
return db.query(Item).offset(pagination["skip"]).limit(pagination["limit"]).all()
Structure APIs with APIRouter for modularity:
# app/routers/items.py
from fastapi import APIRouter
router = APIRouter(
prefix="/items",
tags=["items"],
dependencies=[Depends(verify_token)],
responses={404: {"description": "Not found"}},
)
# app/main.py
from fastapi import FastAPI
from app.routers import items, users
app = FastAPI()
app.include_router(items.router)
app.include_router(users.router, prefix="/api/v1")
Generate better API documentation:
# Generate enhanced OpenAPI docs
bash ./skills/fastapi-api-patterns/scripts/generate-openapi-docs.sh
Endpoint Documentation:
@router.post(
"/items/",
response_model=Item,
status_code=status.HTTP_201_CREATED,
summary="Create a new item",
description="Create a new item with the provided data",
response_description="The created item",
responses={
201: {"description": "Item created successfully"},
400: {"description": "Invalid input data"},
409: {"description": "Item already exists"},
}
)
async def create_item(item: ItemCreate):
"""
Create a new item with all the information:
- **name**: Item name (required, 1-100 characters)
- **description**: Item description (optional, max 500 characters)
- **price**: Item price (required, must be positive)
- **category**: Item category (required)
"""
pass
# Copy chat API example
cp ./skills/fastapi-api-patterns/examples/chat_api.py app/routers/chat.py
Features:
Result: Production-ready chat message API with full CRUD operations
# Copy user management example
cp ./skills/fastapi-api-patterns/examples/user_management.py app/routers/users.py
Features:
Result: Complete user management system with security best practices
# Copy memory endpoints example
cp ./skills/fastapi-api-patterns/examples/memory_endpoints.py app/routers/memory.py
Features:
Result: API for managing AI conversation memory and context
Dependencies:
Optional Dependencies:
Project Structure:
app/
├── main.py
├── routers/
│ ├── __init__.py
│ ├── items.py
│ ├── users.py
│ └── chat.py
├── models/
│ ├── __init__.py
│ └── schemas.py
├── utils/
│ ├── pagination.py
│ └── errors.py
└── dependencies.py
1. Use Response Models:
response_model to control what's returned2. Consistent Error Responses:
error, message, and details3. Pagination Everywhere:
4. Validation and Documentation:
5. Dependencies for Reusability:
6. Versioning:
/api/v1/items)Validate endpoint structure and best practices:
# Validate all endpoints in a router file
bash ./skills/fastapi-api-patterns/scripts/validate-endpoints.sh app/routers/items.py
# What it checks:
# - Response models defined
# - Status codes specified
# - Error handling present
# - Documentation strings
# - Proper HTTP methods
# - Path parameter validation
Database Queries:
Response Size:
Request Validation:
Plugin: fastapi-backend Version: 1.0.0 Category: API Development Skill Type: REST API Patterns