5.5 Example
Sure! Here’s a simple example for each of your folders: routes, models, and services based on a basic “user” concept.
1. app/routes/example.py
Section titled “1. app/routes/example.py”from fastapi import APIRouter, HTTPExceptionfrom typing import Listfrom app.models.example import User, UserCreatefrom app.services.logic import get_users, create_user
router = APIRouter()
@router.get("/users", response_model=List[User])def list_users(): return get_users()
@router.post("/users", response_model=User, status_code=201)def add_user(user_in: UserCreate): user = create_user(user_in) if not user: raise HTTPException(status_code=400, detail="User could not be created") return user2. app/models/example.py
Section titled “2. app/models/example.py”from pydantic import BaseModel, EmailStr
class UserBase(BaseModel): email: EmailStr full_name: str | None = None
class UserCreate(UserBase): password: str
class User(UserBase): id: int
class Config: orm_mode = True3. app/services/logic.py
Section titled “3. app/services/logic.py”from typing import Listfrom app.models.example import User, UserCreate
# Simulate a database with a listfake_db: List[User] = []
def get_users() -> List[User]: return fake_db
def create_user(user_in: UserCreate) -> User: # Basic "unique email" check if any(u.email == user_in.email for u in fake_db): return None
new_user = User(id=len(fake_db) + 1, email=user_in.email, full_name=user_in.full_name) fake_db.append(new_user) return new_userHow this works:
Section titled “How this works:”- Routes handle API endpoints and HTTP.
- Models define request/response data structures.
- Services contain business logic like storing/fetching users.
You can extend this later by:
- Adding real DB integration (e.g. SQLAlchemy).
- Adding password hashing.
- Adding auth.
- Adding validation logic.
Want me to help with any of those?
=================================
Great question!
What is Config and why orm_mode = True?
Section titled “What is Config and why orm_mode = True?”In Pydantic models (used by FastAPI for data validation and serialization), the inner class Config lets you customize model behavior.
orm_mode = True
Section titled “orm_mode = True”- Allows Pydantic to work seamlessly with ORM objects (like SQLAlchemy models).
- It tells Pydantic to read data not only from dictionaries but also from ORM objects (which usually use attributes, not dict keys).
Why is this useful?
Section titled “Why is this useful?”Imagine you have a SQLAlchemy user model like this:
class UserORM(Base): __tablename__ = "users" id = Column(Integer, primary_key=True) email = Column(String) full_name = Column(String)When you query this model, you get an object, not a dict:
user_orm = session.query(UserORM).first()By default, Pydantic expects a dict to parse/serialize. If you pass user_orm directly to a Pydantic model without orm_mode=True, it will error.
With orm_mode=True, you can do:
user = User.from_orm(user_orm)and Pydantic reads attributes (user_orm.email, user_orm.id) correctly.
Summary
Section titled “Summary”class User(BaseModel): id: int email: str
class Config: orm_mode = True # <-- This enables .from_orm() and attribute readingWhen to use?
Section titled “When to use?”- Use
orm_mode=Truewhen your Pydantic models will receive ORM objects, like from SQLAlchemy. - It’s very common in FastAPI apps with database layers.
If you want, I can help you set up a small example with SQLAlchemy + Pydantic + FastAPI that shows this in action!
=====================================
VERSIONING
Yes, definitely! You can support different API versions in FastAPI by versioning your routes, typically by including the version number in the URL path.
Example: Simple URL-based versioning
Section titled “Example: Simple URL-based versioning”from fastapi import FastAPI
app = FastAPI()
@app.get("/api/v1/hello")def hello_v1(): return {"message": "Hello from FastAPI v1!"}
@app.get("/api/v2/hello")def hello_v2(): return {"message": "Hello from FastAPI v2 with new features!"}Clients can then call /api/v1/hello or /api/v2/hello to access the different versions.
More scalable approach: Using APIRouter for versioned groups
Section titled “More scalable approach: Using APIRouter for versioned groups”from fastapi import FastAPI, APIRouter
app = FastAPI()
v1_router = APIRouter(prefix="/api/v1")v2_router = APIRouter(prefix="/api/v2")
@v1_router.get("/hello")def hello_v1(): return {"message": "Hello from FastAPI v1!"}
@v2_router.get("/hello")def hello_v2(): return {"message": "Hello from FastAPI v2 with new features!"}
app.include_router(v1_router)app.include_router(v2_router)This helps keep your versioned routes organized and modular.
If you want, I can also help with other versioning methods like:
- Header-based versioning
- Query parameter versioning
But URL path versioning is the most common and simplest. Want me to show those?