Install
$ agentstack add skill-versoxbt-claude-initial-setup-dependency-injection-fastapi ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
FastAPI Dependency Injection
Use FastAPI's Depends() system to inject shared logic into endpoints: database sessions, authentication, authorization, pagination, and configuration. Dependencies are composable, testable, and handle cleanup automatically.
When to Use
- User creates FastAPI endpoints with shared setup/teardown logic
- User implements authentication or authorization
- User manages database connections or sessions
- User asks about dependency injection or testing FastAPI
- User has duplicated logic across multiple endpoints
Core Patterns
Basic Dependencies
from fastapi import Depends, FastAPI, Query
app = FastAPI()
# Simple dependency -- function that returns a value
async def common_parameters(
skip: int = Query(0, ge=0),
limit: int = Query(100, ge=1, le=1000),
sort_by: str = Query("created_at"),
):
return {"skip": skip, "limit": limit, "sort_by": sort_by}
@app.get("/items")
async def list_items(params: dict = Depends(common_parameters)):
return await fetch_items(**params)
@app.get("/users")
async def list_users(params: dict = Depends(common_parameters)):
return await fetch_users(**params)
Database Session Dependencies
Use generator dependencies for automatic session cleanup.
from typing import AsyncGenerator
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
SessionLocal = async_sessionmaker(engine, expire_on_commit=False)
async def get_db() -> AsyncGenerator[AsyncSession, None]:
"""Yield a database session, ensuring cleanup on exit."""
async with SessionLocal() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
@app.get("/users/{user_id}")
async def get_user(user_id: int, db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User).where(User.id == user_id))
user = result.scalar_one_or_none()
if user is None:
raise HTTPException(status_code=404, detail="User not found")
return user
Security Dependencies
from fastapi import Depends, HTTPException, Security
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
security = HTTPBearer()
async def get_current_user(
credentials: HTTPAuthorizationCredentials = Security(security),
db: AsyncSession = Depends(get_db),
) -> User:
"""Extract and validate the current user from JWT token."""
try:
payload = jwt.decode(
credentials.credentials,
settings.jwt_secret,
algorithms=["HS256"],
)
except jwt.InvalidTokenError:
raise HTTPException(status_code=401, detail="Invalid token")
user_id = payload.get("sub")
if user_id is None:
raise HTTPException(status_code=401, detail="Invalid token payload")
result = await db.execute(select(User).where(User.id == int(user_id)))
user = result.scalar_one_or_none()
if user is None:
raise HTTPException(status_code=401, detail="User not found")
return user
# Role-based authorization as composable dependency
def require_role(required_role: str):
async def check_role(user: User = Depends(get_current_user)) -> User:
if user.role != required_role:
raise HTTPException(status_code=403, detail="Insufficient permissions")
return user
return check_role
@app.delete("/admin/users/{user_id}")
async def delete_user(
user_id: int,
admin: User = Depends(require_role("admin")),
db: AsyncSession = Depends(get_db),
):
await db.execute(delete(User).where(User.id == user_id))
return {"deleted": user_id}
Dependency Chaining
Dependencies can depend on other dependencies. FastAPI resolves the entire graph.
async def get_settings() -> Settings:
return Settings()
async def get_cache(settings: Settings = Depends(get_settings)) -> RedisCache:
return RedisCache(url=settings.redis_url)
async def get_user_service(
db: AsyncSession = Depends(get_db),
cache: RedisCache = Depends(get_cache),
) -> UserService:
return UserService(db=db, cache=cache)
@app.get("/users/{user_id}")
async def get_user(
user_id: int,
service: UserService = Depends(get_user_service),
):
return await service.get_by_id(user_id)
Request-Scoped Dependencies
FastAPI caches dependency results per request by default. The same dependency called multiple times in the same request returns the same instance.
# get_db() is called once per request, even if multiple dependencies use it
@app.post("/transfer")
async def transfer_funds(
transfer: TransferRequest,
sender_service: AccountService = Depends(get_sender_service), # uses get_db
receiver_service: AccountService = Depends(get_receiver_service), # uses get_db
# Both services share the SAME db session within this request
):
...
# To force a fresh instance, use use_cache=False
@app.get("/data")
async def get_data(
db1: AsyncSession = Depends(get_db),
db2: AsyncSession = Depends(get_db, use_cache=False), # Different session
):
...
Router-Level Dependencies
Apply dependencies to all routes in a router or the entire app.
from fastapi import APIRouter
# All routes in this router require authentication
authenticated_router = APIRouter(
prefix="/api/v1",
dependencies=[Depends(get_current_user)],
)
@authenticated_router.get("/profile")
async def get_profile(user: User = Depends(get_current_user)):
return user
# App-level dependencies
app = FastAPI(dependencies=[Depends(verify_api_key)])
Testing with Dependency Overrides
Replace dependencies in tests without modifying production code.
import pytest
from httpx import AsyncClient, ASGITransport
# Create a test database session
async def get_test_db() -> AsyncGenerator[AsyncSession, None]:
async with test_session_factory() as session:
yield session
# Mock current user
async def get_mock_user() -> User:
return User(id=1, name="Test User", email="test@example.com", role="admin")
@pytest.fixture
def client():
app.dependency_overrides[get_db] = get_test_db
app.dependency_overrides[get_current_user] = get_mock_user
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://test") as ac:
yield ac
app.dependency_overrides.clear()
async def test_get_profile(client: AsyncClient):
response = await client.get("/api/v1/profile")
assert response.status_code == 200
assert response.json()["name"] == "Test User"
Anti-Patterns
- Instantiating services in endpoint bodies: Extract to dependencies for reuse
and testability. If you see service = UserService(db) in an endpoint, make it a dependency.
- Not cleaning up resources: Always use generator dependencies (
yield) for
resources that need cleanup (DB sessions, HTTP clients, file handles).
- Hardcoding auth checks in endpoints: Extract to reusable security dependencies.
Depends(require_role("admin")) is clearer and more testable than inline checks.
- Not using dependency overrides in tests: Overriding is the standard way to mock
dependencies. Avoid monkey-patching or modifying production code for tests.
- Fat dependencies: A dependency that does too much. Keep dependencies focused on
one thing: one for DB session, one for auth, one for pagination.
Quick Reference
| Pattern | Syntax | |---|---| | Simple dependency | Depends(my_function) | | Generator (cleanup) | yield inside dependency function | | Security | Security(HTTPBearer()) | | Parameterized | Function returning a dependency function | | Router-level | APIRouter(dependencies=[Depends(...)]) | | Test override | app.dependency_overrides[dep] = mock_dep | | Skip cache | Depends(dep, use_cache=False) | | Class dependency | class MyDep: with __call__ method |
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: VersoXBT
- Source: VersoXBT/claude-initial-setup
- License: MIT
- Homepage: https://github.com/VersoXBT/claude-initial-setup#installation
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.