fromfastapi_otel_commonimportcreate_app# Create app with all middleware enabled and automatic OpenTelemetry instrumentation
app=create_app(title="My API",version="1.0.0",description="Production-ready API with OpenTelemetry")@app.get("/")asyncdefroot():return{"message":"Hello World"}@app.get("/health")asyncdefhealth():return{"status":"healthy"}
Secured Application with Authentication
fromfastapiimportDepends,HTTPExceptionfromfastapi_otel_commonimportcreate_appfromfastapi_otel_common.securityimportget_current_user,get_current_user_optionalfromfastapi_otel_common.core.modelsimportUserBaseapp=create_app(title="Secure API",version="1.0.0")@app.get("/public")asyncdefpublic_endpoint():return{"message":"This is public"}@app.get("/profile")asyncdefget_profile(user:UserBase=Depends(get_current_user)):return{"user_id":user.id,"email":user.email,"name":f"{user.given_name}{user.family_name}"}@app.get("/optional-auth")asyncdefoptional_auth(user:UserBase|None=Depends(get_current_user_optional)):ifuser:return{"message":f"Hello, {user.given_name}!"}return{"message":"Hello, anonymous!"}@app.post("/admin-only")asyncdefadmin_only(user:UserBase=Depends(get_current_user)):# Manual check (roles are preferred now)
if"admin"notinuser.get_roles():raiseHTTPException(status_code=403,detail="Admin access required")return{"message":"Admin access granted"}## Role-Based Access Control (RBAC)
Thelibraryprovidesdedicateddependenciesforroleverification:```pythonfromfastapiimportDependsfromfastapi_otel_common.securityimportRequireRoles,RequireAllRoles,RequireRolesComplexfromfastapi_otel_common.securityimportAnyRole,AllRoles,AnyCondition# 1. OR logic: user needs at least one role
@app.get("/manager-area")asyncdefmanager_area(user:UserBase=Depends(RequireRoles(["admin","manager"]))):return{"message":f"Welcome, {user.given_name}"}# 2. AND logic: user needs all roles
@app.delete("/system/reset")asyncdefsystem_reset(user:UserBase=Depends(RequireAllRoles(["admin","super-user"]))):return{"message":"System reset initiated"}# 3. Complex logic: (admin AND auditor) OR tech-lead
complex_logic=AnyCondition(AllRoles(["admin","auditor"]),AnyRole(["tech-lead"]))@app.post("/critical-op")asyncdefcritical_op(user:UserBase=Depends(RequireRolesComplex(complex_logic))):return{"message":"Operation successful"}
## Application with Database
```python
from fastapi import Depends, HTTPException
from sqlalchemy import Column, Integer, String, select
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel
from fastapi_otel_common import create_app
from fastapi_otel_common.database import BaseModel as DBBase, get_db_session
from fastapi_otel_common.security import get_current_user
from fastapi_otel_common.core.models import UserBase
# Database Model
class Item(DBBase):
__tablename__ = "items"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
description = Column(String)
owner_id = Column(String)
# Pydantic Models
class ItemCreate(BaseModel):
title: str
description: str
class ItemResponse(BaseModel):
id: int
title: str
description: str
owner_id: str
class Config:
from_attributes = True
# Create app
app = create_app(title="Items API", version="1.0.0")
# Routes
@app.post("/items", response_model=ItemResponse)
async def create_item(
item_data: ItemCreate,
user: UserBase = Depends(get_current_user),
db: AsyncSession = Depends(get_db_session)
):
item = Item(
title=item_data.title,
description=item_data.description,
owner_id=user.id
)
db.add(item)
await db.commit()
await db.refresh(item)
return item
@app.get("/items", response_model=list[ItemResponse])
async def list_items(
user: UserBase = Depends(get_current_user),
db: AsyncSession = Depends(get_db_session)
):
result = await db.execute(
select(Item).where(Item.owner_id == user.id)
)
return result.scalars().all()
@app.get("/items/{item_id}", response_model=ItemResponse)
async def get_item(
item_id: int,
user: UserBase = Depends(get_current_user),
db: AsyncSession = Depends(get_db_session)
):
result = await db.execute(
select(Item).where(Item.id == item_id, Item.owner_id == user.id)
)
item = result.scalar_one_or_none()
if not item:
raise HTTPException(status_code=404, detail="Item not found")
return item
@app.delete("/items/{item_id}")
async def delete_item(
item_id: int,
user: UserBase = Depends(get_current_user),
db: AsyncSession = Depends(get_db_session)
):
result = await db.execute(
select(Item).where(Item.id == item_id, Item.owner_id == user.id)
)
item = result.scalar_one_or_none()
if not item:
raise HTTPException(status_code=404, detail="Item not found")
await db.delete(item)
await db.commit()
return {"message": "Item deleted"}
Custom Rate Limiting
fromfastapiimportRequestfromfastapi_otel_commonimportcreate_appapp=create_app(title="Rate Limited API",version="1.0.0")# Access the limiter from app state
limiter=app.state.limiter@app.get("/standard")asyncdefstandard_endpoint():# Uses global rate limit (from env vars)
return{"message":"Standard rate limit"}@app.get("/expensive")@limiter.limit("5/minute")asyncdefexpensive_endpoint(request:Request):# Custom rate limit: 5 requests per minute
return{"message":"Expensive operation"}@app.get("/premium")@limiter.limit("100/minute;1000/hour")asyncdefpremium_endpoint(request:Request):# Multiple limits
return{"message":"Premium endpoint"}
Manual Middleware Configuration
fromfastapiimportFastAPIfromfastapi_otel_commonimport(ErrorHandlingMiddleware,LoggingMiddleware,RateLimitMiddleware,RequestIDMiddleware,SecurityHeadersMiddleware,)app=FastAPI(title="Custom Middleware",version="1.0.0")# Add middleware manually in order (last added executes first)
app.add_middleware(ErrorHandlingMiddleware)app.add_middleware(SecurityHeadersMiddleware)app.add_middleware(LoggingMiddleware)app.add_middleware(RateLimitMiddleware,requests_per_minute=100,requests_per_hour=5000)app.add_middleware(RequestIDMiddleware)# Note: OpenTelemetry instrumentation must be added manually when not using create_app()
# from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
# FastAPIInstrumentor.instrument_app(app)
@app.get("/")asyncdefroot():return{"message":"Custom middleware setup"}