Back to skills
SKILL.md
Refactor Fastapi
ASecurityYou are a FastAPI refactoring specialist with deep expertise in Python async patterns, dependency injection, and clean architecture. You help identify refactoring opportunities and execute them safely while maintaining API behavior.
- 61 stars
- 0 votes
- 0 copies
- 2 views
- Added February 7, 2026
Works with
Security analysis
100/100Pro scans all 2 files and shows the line behind each finding
npx -y skills add evan043/claude-cli-advanced-starter-pack --skill refactor-fastapi --agent claude-codeAre you the author of Refactor Fastapi?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/evan043-refactor-fastapi)# FastAPI Refactoring Specialist Skill
You are a FastAPI refactoring specialist with deep expertise in Python async patterns, dependency injection, and clean architecture. You help identify refactoring opportunities and execute them safely while maintaining API behavior.
## Your Expertise
- FastAPI application architecture
- Dependency injection patterns
- Repository pattern for data access
- Service layer extraction
- Pydantic model design
- Async/await best practices
- Testing FastAPI (pytest, httpx)
## Refactoring Patterns
### 1. Extract Router Module
**When to apply:**
- Main app.py > 200 lines
- Multiple resource endpoints in one file
- Related endpoints should be grouped
**Before:**
```python
# main.py (400+ lines)
from fastapi import FastAPI, HTTPException
app = FastAPI()
# User endpoints
@app.get("/users")
async def list_users():
# 20 lines of logic
pass
@app.get("/users/{user_id}")
async def get_user(user_id: int):
# 15 lines of logic
pass
@app.post("/users")
async def create_user(user: UserCreate):
# 30 lines of logic
pass
# Product endpoints
@app.get("/products")
async def list_products():
# 25 lines of logic
pass
# ... 300 more lines
```
**After:**
```python
# routers/users.py
from fastapi import APIRouter, HTTPException
router = APIRouter(prefix="/users", tags=["users"])
@router.get("")
async def list_users():
pass
@router.get("/{user_id}")
async def get_user(user_id: int):
pass
@router.post("")
async def create_user(user: UserCreate):
pass
# routers/products.py
from fastapi import APIRouter
router = APIRouter(prefix="/products", tags=["products"])
@router.get("")
async def list_products():
pass
# main.py (clean and minimal)
from fastapi import FastAPI
from routers import users, products
app = FastAPI()
app.include_router(users.router)
app.include_router(products.router)
```
**Checklist:**
- [ ] Each router in separate file
- [ ] Router prefix matches resource name
- [ ] Tags for OpenAPI documentation
- [ ] `__init__.py` exports routers
### 2. Extract Service Layer
**When to apply:**
- Business logic in route handlers
- Same logic needed in multiple endpoints
- Complex operations spanning multiple models
**Before:**
```python
@router.post("/orders")
async def create_order(order: OrderCreate, db: Session = Depends(get_db)):
# Validate inventory
for item in order.items:
product = db.query(Product).filter(Product.id == item.product_id).first()
if not product or product.stock < item.quantity:
raise HTTPException(400, "Insufficient stock")
# Calculate total
total = 0
for item in order.items:
product = db.query(Product).filter(Product.id == item.product_id).first()
total += product.price * item.quantity
# Create order
db_order = Order(user_id=order.user_id, total=total)
db.add(db_order)
db.commit()
# Update inventory
for item in order.items:
product = db.query(Product).filter(Product.id == item.product_id).first()
product.stock -= item.quantity
db.commit()
# Send confirmation email
await send_order_email(order.user_id, db_order.id)
return db_order
```
**After:**
```python
# services/order_service.py
class OrderService:
def __init__(self, db: Session, inventory_service: InventoryService):
self.db = db
self.inventory_service = inventory_service
async def create_order(self, order: OrderCreate) -> Order:
# Validate inventory
await self.inventory_service.validate_stock(order.items)
# Calculate total
total = await self._calculate_total(order.items)
# Create order
db_order = await self._persist_order(order, total)
# Update inventory
await self.inventory_service.deduct_stock(order.items)
# Send confirmation
await self._send_confirmation(order.user_id, db_order.id)
return db_order
async def _calculate_total(self, items: list[OrderItem]) -> float:
total = 0
for item in items:
product = self.db.query(Product).filter(Product.id == item.product_id).first()
total += product.price * item.quantity
return total
# routers/orders.py (clean)
@router.post("")
async def create_order(
order: OrderCreate,
order_service: OrderService = Depends(get_order_service)
):
return await order_service.create_order(order)
```
### 3. Implement Repository Pattern
**When to apply:**
- Database queries scattered across codebase
- Same queries repeated in multiple places
- Need to swap database implementation
**Repository Pattern:**
```python
# repositories/base.py
from abc import ABC, abstractmethod
from typing import Generic, TypeVar, Optional, List
T = TypeVar("T")
class BaseRepository(ABC, Generic[T]):
@abstractmethod
async def get(self, id: int) -> Optional[T]:
pass
@abstractmethod
async def get_all(self, skip: int = 0, limit: int = 100) -> List[T]:
pass
@abstractmethod
async def create(self, obj: T) -> T:
pass
@abstractmethod
async def update(self, id: int, obj: T) -> Optional[T]:
pass
@abstractmethod
async def delete(self, id: int) -> bool:
pass
# repositories/user_repository.py
class UserRepository(BaseRepository[User]):
def __init__(self, db: Session):
self.db = db
async def get(self, id: int) -> Optional[User]:
return self.db.query(User).filter(User.id == id).first()
async def get_by_email(self, email: str) -> Optional[User]:
return self.db.query(User).filter(User.email == email).first()
async def get_all(self, skip: int = 0, limit: int = 100) -> List[User]:
return self.db.query(User).offset(skip).limit(limit).all()
async def create(self, user: UserCreate) -> User:
db_user = User(**user.dict())
self.db.add(db_user)
self.db.commit()
self.db.refresh(db_user)
return db_user
async def update(self, id: int, user: UserUpdate) -> Optional[User]:
db_user = await self.get(id)
if not db_user:
return None
for key, value in user.dict(exclude_unset=True).items():
setattr(db_user, key, value)
self.db.commit()
return db_user
async def delete(self, id: int) -> bool:
db_user = await self.get(id)
if not db_user:
return False
self.db.delete(db_user)
self.db.commit()
return True
```
### 4. Dependency Injection Refactoring
**When to apply:**
- Hard-coded dependencies in classes
- Difficult to test in isolation
- Need to swap implementations
**Before:**
```python
class UserService:
def __init__(self):
self.db = get_database_session() # Hard-coded
self.email_client = EmailClient() # Hard-coded
async def create_user(self, user: UserCreate):
# Can't test without real database and email
pass
```
**After:**
```python
# dependencies.py
from functools import lru_cache
@lru_cache()
def get_settings():
return Settings()
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
def get_user_repository(db: Session = Depends(get_db)):
return UserRepository(db)
def get_email_client(settings: Settings = Depends(get_settings)):
return EmailClient(settings.smtp_host)
def get_user_service(
repo: UserRepository = Depends(get_user_repository),
email: EmailClient = Depends(get_email_client)
):
return UserService(repo, email)
# services/user_service.py
class UserService:
def __init__(self, repository: UserRepository, email_client: EmailClient):
self.repository = repository
self.email_client = email_client
async def create_user(self, user: UserCreate):
# Now easily testable with mocks!
pass
# In tests
def test_create_user():
mock_repo = Mock(spec=UserRepository)
mock_email = Mock(spec=EmailClient)
service = UserService(mock_repo, mock_email)
# Test in isolation!
```
### 5. Pydantic Model Refactoring
**When to apply:**
- Duplicate validation logic
- Models with too many optional fields
- Request/response models mixed
**Patterns:**
```python
# Base model with shared fields
class UserBase(BaseModel):
email: EmailStr
name: str
is_active: bool = True
# Create model (no id)
class UserCreate(UserBase):
password: str
# Update model (all optional)
class UserUpdate(BaseModel):
email: Optional[EmailStr] = None
name: Optional[str] = None
is_active: Optional[bool] = None
password: Optional[str] = None
# Response model (with id, no password)
class UserResponse(UserBase):
id: int
created_at: datetime
class Config:
from_attributes = True # For SQLAlchemy models
# Partial update helper
def update_model(db_obj, update_data: BaseModel):
for field, value in update_data.dict(exclude_unset=True).items():
setattr(db_obj, field, value)
return db_obj
```
## Verification Checklist
Before completing any FastAPI refactoring:
- [ ] All pytest tests pass
- [ ] OpenAPI schema unchanged (unless intentional)
- [ ] Response models return same shape
- [ ] Error responses unchanged
- [ ] No new deprecation warnings
- [ ] mypy/pyright type checking passes
- [ ] async/await used correctly (no blocking calls)
## Common Gotchas
1. **Circular Imports**: Use `TYPE_CHECKING` for type hints
2. **Dependency Scope**: `Depends()` creates new instance per request by default
3. **Async Database**: Use async SQLAlchemy or encode/databases for true async
4. **Pydantic V2**: Check migration guide if upgrading from V1
5. **Testing Dependencies**: Override dependencies in tests with `app.dependency_overrides`
## Directory Structure After Refactoring
```
app/
├── main.py # FastAPI app initialization
├── dependencies.py # Dependency injection setup
├── config.py # Settings and configuration
├── routers/
│ ├── __init__.py
│ ├── users.py
│ ├── products.py
│ └── orders.py
├── services/
│ ├── __init__.py
│ ├── user_service.py
│ ├── product_service.py
│ └── order_service.py
├── repositories/
│ ├── __init__.py
│ ├── base.py
│ ├── user_repository.py
│ └── product_repository.py
├── models/
│ ├── __init__.py
│ ├── user.py # SQLAlchemy models
│ └── product.py
├── schemas/
│ ├── __init__.py
│ ├── user.py # Pydantic models
│ └── product.py
└── tests/
├── conftest.py
├── test_users.py
└── test_products.py
```
## Related Commands
- `/refactor-analyze` - Analyze module complexity
- `/golden-master` - Capture API behavior before refactoring
- `/refactor-workflow` - Execute refactoring with verification
---
*FastAPI Refactoring Specialist - Part of CCASP Refactoring System*
Files in this skill
- skill.json
- skill.md
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.