"""
FastAPI Complete API Template
Production-ready FastAPI application with authentication, CRUD, and best practices.
"""
from fastapi import FastAPI, HTTPException, Depends, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel, EmailStr, Field
from typing import Optional, List
from datetime import datetime, timedelta
import hashlib
import secrets
# ============================================
# Models
# ============================================
class UserCreate(BaseModel):
email: EmailStr
name: str = Field(..., min_length=2, max_length=50)
password: str = Field(..., min_length=8)
class UserResponse(BaseModel):
id: int
email: str
name: str
created_at: datetime
class Config:
from_attributes = True
class UserUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=2, max_length=50)
email: Optional[EmailStr] = None
class Token(BaseModel):
access_token: str
token_type: str = "bearer"
class LoginRequest(BaseModel):
email: EmailStr
password: str
# ============================================
# Database (In-Memory for Demo)
# ============================================
class Database:
def __init__(self):
self.users: dict[int, dict] = {}
self.tokens: dict[str, int] = {} # token -> user_id
self.next_id = 1
def create_user(self, data: UserCreate) -> dict:
user = {
"id": self.next_id,
"email": data.email,
"name": data.name,
"password_hash": hashlib.sha256(data.password.encode()).hexdigest(),
"created_at": datetime.utcnow()
}
self.users[self.next_id] = user
self.next_id += 1
return user
def get_user(self, user_id: int) -> Optional[dict]:
return self.users.get(user_id)
def get_user_by_email(self, email: str) -> Optional[dict]:
for user in self.users.values():
if user["email"] == email:
return user
return None
def get_all_users(self) -> List[dict]:
return list(self.users.values())
def update_user(self, user_id: int, data: UserUpdate) -> Optional[dict]:
user = self.users.get(user_id)
if not user:
return None
if data.name:
user["name"] = data.name
if data.email:
user["email"] = data.email
return user
def delete_user(self, user_id: int) -> bool:
if user_id in self.users:
del self.users[user_id]
return True
return False
def create_token(self, user_id: int) -> str:
token = secrets.token_urlsafe(32)
self.tokens[token] = user_id
return token
def verify_token(self, token: str) -> Optional[int]:
return self.tokens.get(token)
db = Database()
# ============================================
# Auth
# ============================================
security = HTTPBearer()
async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)) -> dict:
token = credentials.credentials
user_id = db.verify_token(token)
if not user_id:
raise HTTPException(status_code=401, detail="Invalid token")
user = db.get_user(user_id)
if not user:
raise HTTPException(status_code=401, detail="User not found")
return user
# ============================================
# App Setup
# ============================================
app = FastAPI(
title="Code-MCP API Template",
description="Production-ready FastAPI template",
version="1.0.0"
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ============================================
# Routes
# ============================================
@app.get("/health")
async def health_check():
return {"status": "healthy", "timestamp": datetime.utcnow().isoformat()}
@app.post("/auth/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
async def register(data: UserCreate):
if db.get_user_by_email(data.email):
raise HTTPException(status_code=400, detail="Email already registered")
user = db.create_user(data)
return user
@app.post("/auth/login", response_model=Token)
async def login(data: LoginRequest):
user = db.get_user_by_email(data.email)
if not user:
raise HTTPException(status_code=401, detail="Invalid credentials")
password_hash = hashlib.sha256(data.password.encode()).hexdigest()
if user["password_hash"] != password_hash:
raise HTTPException(status_code=401, detail="Invalid credentials")
token = db.create_token(user["id"])
return {"access_token": token}
@app.get("/users", response_model=List[UserResponse])
async def get_users(current_user: dict = Depends(get_current_user)):
return db.get_all_users()
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int, current_user: dict = Depends(get_current_user)):
user = db.get_user(user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
@app.put("/users/{user_id}", response_model=UserResponse)
async def update_user(user_id: int, data: UserUpdate, current_user: dict = Depends(get_current_user)):
user = db.update_user(user_id, data)
if not user:
raise HTTPException(status_code=404, detail="User not found")
return user
@app.delete("/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(user_id: int, current_user: dict = Depends(get_current_user)):
if not db.delete_user(user_id):
raise HTTPException(status_code=404, detail="User not found")
# ============================================
# Run
# ============================================
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)