Skip to content

5.5 Example

Sure! Here’s a simple example for each of your folders: routes, models, and services based on a basic “user” concept.


from fastapi import APIRouter, HTTPException
from typing import List
from app.models.example import User, UserCreate
from 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 user

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 = True

from typing import List
from app.models.example import User, UserCreate
# Simulate a database with a list
fake_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_user

  • 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!

In Pydantic models (used by FastAPI for data validation and serialization), the inner class Config lets you customize model behavior.


  • 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).

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.


class User(BaseModel):
id: int
email: str
class Config:
orm_mode = True # <-- This enables .from_orm() and attribute reading

  • Use orm_mode=True when 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.

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?