How to Use FastCRUD with Existing FastAPI Applications: A Complete Integration Guide
FastCRUD integrates with existing FastAPI applications by generating async CRUD endpoints through the crud_router function, which creates an APIRouter that can be directly included in your main FastAPI app using standard include_router patterns.
The benavlabs/fastcrud library provides a thin abstraction layer that adds async-ready, feature-rich CRUD operations on top of SQLAlchemy 2.x (or SQLModel) models. By leveraging the crud_router builder and EndpointCreator classes, you can wire fully functional REST endpoints into existing FastAPI projects without refactoring your database layer or application structure.
Understanding FastCRUD's Architecture
FastCRUD operates through three distinct layers that work together to generate endpoints while preserving your existing FastAPI setup.
The Core CRUD Layer
The FastCRUD class in [fastcrud/crud/fast_crud.py](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/crud/fast_crud.py) provides generic methods including create, get, get_multi, get_joined, update, delete, db_delete, upsert, and count. This class handles advanced filtering, sorting, cursor-pagination, and multi-dialect upserts while remaining completely model-agnostic.
The Router Builder
The [fastcrud/endpoint/crud_router.py](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/endpoint/crud_router.py#L19-L84) file contains the crud_router convenience function (lines 19-84). This function instantiates EndpointCreator and returns a fully configured APIRouter that you can immediately include in your existing FastAPI application using app.include_router().
The Endpoint Creator
The [fastcrud/endpoint/endpoint_creator.py](https://github.com/benavlabs/fastcrud/blob/main/fastcrud/endpoint/endpoint_creator.py#L62-L140) class implements the actual endpoint functions (_create_item, _read_item, _read_items, etc.) on lines 62-140. It handles dependency injection, automatic relationship inclusion, filter validation, and response-model conversion before registering routes with the router.
Step-by-Step Integration Guide
Integrating FastCRUD into an existing FastAPI application requires four main steps: defining schemas, creating a session dependency, generating the router, and including it in your app.
Define Your SQLAlchemy Models and Pydantic Schemas
FastCRUD requires SQLAlchemy 2.x declarative models (or SQLModel) and separate Pydantic schemas for create, update, and read operations.
# app/models.py
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass
class Item(Base):
__tablename__ = "items"
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
description = Column(String)
# app/schemas.py
from pydantic import BaseModel
class ItemCreateSchema(BaseModel):
name: str
description: str | None = None
class ItemReadSchema(BaseModel):
id: int
name: str
description: str | None = None
Create an Async Session Dependency
FastCRUD expects a callable that returns an AsyncSession, typically wrapped in FastAPI's Depends.
# app/database.py
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
from typing import AsyncGenerator
DATABASE_URL = "sqlite+aiosqlite:///./test.db"
engine = create_async_engine(DATABASE_URL, echo=False)
AsyncSessionLocal = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async def get_session() -> AsyncGenerator[AsyncSession, None]:
async with AsyncSessionLocal() as session:
yield session
Generate the CRUD Router
Use the crud_router function to create an APIRouter instance configured for your model.
# app/main.py
from fastapi import FastAPI
from fastcrud import crud_router
from .database import get_session, engine
from .models import Base, Item
from .schemas import ItemCreateSchema, ItemReadSchema
app = FastAPI()
@app.on_event("startup")
async def init_db():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
item_router = crud_router(
session=get_session,
model=Item,
create_schema=ItemCreateSchema,
update_schema=ItemCreateSchema,
select_schema=ItemReadSchema,
path="/items",
tags=["Items"],
)
app.include_router(item_router)
The crud_router function (lines 19-84 in fastcrud/endpoint/crud_router.py) instantiates EndpointCreator and returns a router that implements POST /, GET /{pk}, GET /, PATCH /{pk}, and DELETE /{pk} endpoints.
Advanced Integration Patterns
Once basic integration is working, you can customize the generated endpoints to fit your existing application's requirements.
Adding Authentication Dependencies
Inject custom dependencies into specific CRUD operations using the read_deps, create_deps, update_deps, and delete_deps parameters.
from fastapi import Depends, HTTPException, status
from .deps import get_current_user
item_router = crud_router(
session=get_session,
model=Item,
create_schema=ItemCreateSchema,
update_schema=ItemCreateSchema,
select_schema=ItemReadSchema,
path="/items",
tags=["Items"],
read_deps=[get_current_user],
update_deps=[get_current_user],
delete_deps=[get_current_user],
)
The EndpointCreator.add_routes_to_router method (lines 77-84 in fastcrud/endpoint/endpoint_creator.py) receives these dependency lists and passes them to FastAPI's router.add_api_route via the inject_dependencies utility.
Enabling Automatic Relationship Joins
FastCRUD can automatically detect and join SQLAlchemy relationships, returning nested data structures in your API responses.
# models.py
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
class Category(Base):
__tablename__ = "categories"
id = Column(Integer, primary_key=True)
name = Column(String)
class Item(Base):
__tablename__ = "items"
id = Column(Integer, primary_key=True)
name = Column(String)
category_id = Column(Integer, ForeignKey("categories.id"))
category = relationship("Category", backref="items")
# schemas.py
class CategoryReadSchema(BaseModel):
id: int
name: str
class ItemReadSchema(BaseModel):
id: int
name: str
category: CategoryReadSchema | None = None
# main.py
item_router = crud_router(
session=get_session,
model=Item,
create_schema=ItemCreateSchema,
update_schema=ItemCreateSchema,
select_schema=ItemReadSchema,
path="/items",
tags=["Items"],
include_relationships=True,
nest_joins=True,
)
The join configuration logic resides in EndpointCreator._get_join_params (lines 61-84 in fastcrud/endpoint/endpoint_creator.py), which builds the parameters for FastCRUD.get_multi_joined and get_joined calls.
Custom Endpoints with EndpointCreator
For complex business logic that extends beyond standard CRUD, use EndpointCreator directly to mix auto-generated and custom routes.
from fastcrud import EndpointCreator
from fastapi import APIRouter, Depends
from sqlalchemy import select, func
custom_creator = EndpointCreator(
session=get_session,
model=Item,
create_schema=ItemCreateSchema,
update_schema=ItemCreateSchema,
select_schema=ItemReadSchema,
)
async def price_summary(
category_id: int | None = None,
db: AsyncSession = Depends(get_session),
):
query = select(func.sum(Item.price))
if category_id is not None:
query = query.where(Item.category_id == category_id)
result = await db.execute(query)
total = result.scalar_one_or_none() or 0
return {"total_price": float(total)}
# Add standard CRUD routes
custom_creator.add_routes_to_router()
# Add custom business logic endpoint
custom_creator.add_custom_route(
endpoint=price_summary,
methods=["GET"],
path="/price-summary",
tags=["Analytics"],
summary="Total price of items (optional filter by category)",
)
app.include_router(custom_creator.router, prefix="/items")
The add_custom_route method (lines 71-84 in fastcrud/endpoint/endpoint_creator.py) forwards to FastAPI's router.add_api_route, allowing seamless integration of custom handlers alongside library-generated endpoints.
Summary
- FastCRUD provides a model-agnostic CRUD layer in
fastcrud/crud/fast_crud.pywith async operations, advanced filtering, and relationship joining. - The
crud_routerfunction infastcrud/endpoint/crud_router.pygenerates a completeAPIRouterthat plugs into existing FastAPI applications viaapp.include_router(). EndpointCreatorinfastcrud/endpoint/endpoint_creator.pyhandles endpoint implementation, dependency injection, and custom route registration.- Integration requires only four steps: define schemas, create an async session dependency, call
crud_router, and include the resulting router. - Advanced features include per-endpoint authentication dependencies, automatic SQLAlchemy relationship joining, and custom endpoint mixing through direct
EndpointCreatorusage.
Frequently Asked Questions
Can I use FastCRUD with an existing SQLAlchemy database setup?
Yes. FastCRUD is designed to work with existing SQLAlchemy 2.x declarative models and database engines. You do not need to modify your table definitions or migration scripts. Simply pass your existing model class to the crud_router function along with your current async session dependency, and FastCRUD will inspect the model metadata to generate appropriate endpoints.
How do I add authentication to specific CRUD endpoints?
Use the dependency injection parameters in crud_router or EndpointCreator. Pass a list of dependency callables to read_deps, create_deps, update_deps, or delete_deps to secure specific operations. These dependencies are forwarded to FastAPI's router.add_api_route via the inject_dependencies utility in EndpointCreator.add_routes_to_router (lines 77-84), ensuring standard FastAPI dependency resolution.
Does FastCRUD support automatic joining of related tables?
Yes. Set include_relationships=True when calling crud_router to enable automatic detection of SQLAlchemy relationships. Use nest_joins=True to return nested JSON structures rather than flat column results. The join configuration logic resides in EndpointCreator._get_join_params (lines 61-84), which builds parameters for FastCRUD.get_multi_joined and get_joined methods to handle the actual database queries.
Can I mix auto-generated CRUD routes with custom business logic endpoints?
Absolutely. Instantiate EndpointCreator directly instead of using the crud_router convenience function. Call add_routes_to_router() to register standard CRUD endpoints, then use add_custom_route() (lines 71-84 in endpoint_creator.py) to register bespoke endpoints that mix CRUD operations with custom business logic. Finally, include the EndpointCreator.router in your FastAPI app using app.include_router().
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →