F
FasORM
v0.1.0

FastAPI Integration Tutorial

FasORM was designed specifically for FastAPI. Follow this guide to integrate FasORM models into your async FastAPI web applications.

1. Define Models

Define your domain models with relationships in app/models/:

app/models/blog.py
from fasorm import Model, String, Text, Boolean, HasMany, BelongsTo

class User(Model):
    name = String(100)
    email = String(255, unique=True)
    posts = HasMany("Post")

class Post(Model):
    title = String(200)
    content = Text()
    is_published = Boolean(default=True)
    user = BelongsTo("User")

2. Define Pydantic Schemas

Define request and response schemas for FastAPI validation:

app/schemas.py
from pydantic import BaseModel, EmailStr
from typing import Optional, List

class UserCreate(BaseModel):
    name: str
    email: EmailStr

class PostCreate(BaseModel):
    title: str
    content: str
    user_id: int

3. Complete FastAPI Application

Here is a complete, working main.py implementing CRUD routes, pagination, and relationship loading:

main.py
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException, Query
from fasorm import init_db
from app.models.blog import User, Post
from app.schemas import UserCreate, PostCreate

# Lifespan context manager for database initialization
@asynccontextmanager
async def lifespan(app: FastAPI):
    init_db(os.getenv("DB_URL", "sqlite+aiosqlite:///app.db"))
    yield

app = FastAPI(title="FasORM FastAPI Demo", lifespan=lifespan)

@app.post("/users", status_code=211)
async def create_user(payload: UserCreate):
    user = await User.create(**payload.model_dump())
    return user.to_dict()

@app.get("/users")
async def list_users(page: int = Query(1, ge=1), per_page: int = Query(15, le=100)):
    # Paginate users with related posts count attached
    result = await User.with_count("posts").paginate(per_page=per_page, page=page)
    return result.to_dict()

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    # Eager-load user's posts
    user = await User.with_("posts").where(id=user_id).first()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user.to_dict()

@app.post("/posts")
async def create_post(payload: PostCreate):
    post = await Post.create(**payload.model_dump())
    return post.to_dict()

@app.delete("/posts/{post_id}")
async def delete_post(post_id: int):
    post = await Post.find(post_id)
    if not post:
        raise HTTPException(status_code=404, detail="Post not found")
    await post.delete()
    return {"status": "deleted"}