Skip to main content

FastAPI CRUD router and repository toolkit.

Project description

fastapi-crud-engine

Async CRUD engine for FastAPI + SQLAlchemy with built-in filtering, pagination, soft delete, audit logs, cache, rate limiting, import/export, and webhooks.

fastapi-crud-engine helps you ship consistent CRUD APIs faster with less boilerplate and more production-ready defaults.

PyPI version Python versions License

Table of Contents

Features

  • Automatic CRUD router:
    • GET /, GET /{pk}, POST /, PUT /{pk}, PATCH /{pk}, DELETE /{pk}
  • Soft delete and restore endpoints
  • Advanced FilterSet support:
    • exact, search, icontains, ordering, range, in, isnull
  • Pagination with consistent response schema
  • Bulk create endpoint (/bulk)
  • CSV/XLSX import and export (/import, /export)
  • Audit trail for create/update/delete/restore
  • Cache backend (in-memory or Redis)
  • Rate limiting (in-memory or Redis)
  • Webhook delivery (http or celery)
  • Lifecycle hooks (before_*, after_*)
  • Field-level permissions by role
  • Built-in exception mapping for FastAPI

Installation

Requirements: Python >=3.11

Recommended: install in a virtual environment

python -m venv .venv
source .venv/bin/activate
python -m pip install -U pip

Install from PyPI

python -m pip install fastapi-crud-engine

Install optional extras

python -m pip install "fastapi-crud-engine[excel,redis,celery]"
  • excel: enables XLSX import/export via openpyxl
  • redis: enables Redis cache and Redis rate limiter
  • celery: enables async webhook delivery through Celery workers

Install from source (local development)

git clone https://github.com/Lakeserl/auto-crud.git
cd auto-crud
python -m pip install -e ".[dev]"

Install from TestPyPI (if you publish test builds)

python -m pip install "fastapi<1" "pydantic<3" "SQLAlchemy<3" "httpx<1" "python-dateutil<3"
python -m pip install --index-url https://test.pypi.org/simple --no-deps fastapi-crud-engine==0.1.3

Quickstart

from contextlib import asynccontextmanager
from typing import AsyncGenerator

from fastapi import FastAPI
from pydantic import BaseModel
from sqlalchemy import String
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column

from fastapi_crud_engine.core.handlers import register_exception_handlers
from fastapi_crud_engine.core.mixins import SoftDeleteMixin
from fastapi_crud_engine.router import CRUDRouter

engine = create_async_engine("sqlite+aiosqlite:///./app.db")
SessionLocal = async_sessionmaker(engine, expire_on_commit=False, class_=AsyncSession)


class Base(DeclarativeBase):
    pass


class User(SoftDeleteMixin, Base):
    __tablename__ = "users"
    id: Mapped[int] = mapped_column(primary_key=True)
    email: Mapped[str] = mapped_column(String(255), unique=True, index=True)


class UserSchema(BaseModel):
    id: int | None = None
    email: str
    model_config = {"from_attributes": True}


async def get_db() -> AsyncGenerator[AsyncSession, None]:
    async with SessionLocal() as session:
        yield session


@asynccontextmanager
async def lifespan(app: FastAPI):
    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    yield


app = FastAPI(lifespan=lifespan)
register_exception_handlers(app)

app.include_router(
    CRUDRouter(
        model=User,
        schema=UserSchema,
        db=get_db,
        prefix="/users",
        soft_delete=True,
    )
)

Run:

uvicorn main:app --reload

Core Usage

Endpoints generated by CRUDRouter

For prefix="/users":

  • GET /users
  • GET /users/{pk}
  • POST /users
  • PUT /users/{pk}
  • PATCH /users/{pk}
  • DELETE /users/{pk}
  • POST /users/bulk
  • GET /users/export?fmt=csv|xlsx
  • POST /users/import
  • GET /users/deleted (when soft_delete=True)
  • POST /users/{pk}/restore (when soft_delete=True)

Feature-by-Feature Usage

1. Filtering and pagination

from fastapi_crud_engine.core.filters import FilterSet

router = CRUDRouter(
    ...,
    filterset=FilterSet(
        fields=["role", "status"],
        search_fields=["email", "name"],
        ordering_fields=["id", "created_at", "email"],
        range_fields=["created_at"],
        in_fields=["role"],
        nullable_fields=["deleted_at"],
        default_ordering="-id",
    ),
)

Example queries:

GET /users?page=1&size=20
GET /users?role=admin
GET /users?search=john
GET /users?ordering=-created_at,email
GET /users?created_at__gte=2026-01-01&created_at__lte=2026-12-31
GET /users?role__in=admin,editor
GET /users?deleted_at__isnull=true

2. Soft delete and restore

Your model must inherit SoftDeleteMixin.

from fastapi_crud_engine.core.mixins import SoftDeleteMixin

class User(SoftDeleteMixin, Base):
    ...

router = CRUDRouter(..., soft_delete=True)

When enabled:

  • DELETE performs soft delete (deleted_at is set)
  • GET /{prefix}/deleted lists soft-deleted records
  • POST /{prefix}/{pk}/restore restores a record

3. Audit trail

router = CRUDRouter(..., audit_trail=True)

This logs create/update/delete/restore operations to the audit model generated by build_audit_log_model.

4. Cache

from fastapi_crud_engine.features.cache import Cache

cache = Cache(ttl=60, backend="memory")
# or Cache(ttl=60, backend="redis", redis_url="redis://localhost:6379/0")

router = CRUDRouter(
    ...,
    cache=cache,
    cache_endpoints=["list", "get"],
)

Write operations automatically invalidate model cache keys.

5. Rate limiting

from fastapi_crud_engine.features.rate_limiter import RateLimiter

router = CRUDRouter(
    ...,
    rate_limit=RateLimiter(requests=100, window=60),
)

Default key strategy is client IP. If limit is exceeded, API returns 429 with Retry-After.

6. Field-level permissions

from fastapi_crud_engine.core.permissions import FieldPermissions

permissions = FieldPermissions(
    hidden_by_default=["password_hash"],
    read={"admin": "__all__", "user": ["id", "email", "role"]},
    write={"admin": "__all__", "user": ["email"]},
)

router = CRUDRouter(..., field_permissions=permissions)

Role is read from request.state.role (fallback: "user").

7. Lifecycle hooks

from fastapi_crud_engine.router import CRUDHooks

async def before_create(db, payload):
    ...

async def after_create(db, obj):
    ...

router = CRUDRouter(
    ...,
    hooks=CRUDHooks(
        before_create=before_create,
        after_create=after_create,
    ),
)

Available hooks:

  • before_create, after_create
  • before_update, after_update
  • before_delete, after_delete
  • before_restore, after_restore

8. Webhooks

from fastapi_crud_engine.features.webhooks import WebhookConfig, WebhookEndpoint

webhooks = WebhookConfig(
    delivery="http",  # or "celery"
    max_retries=3,
    timeout=10,
    endpoints=[
        WebhookEndpoint(
            url="https://example.com/webhook",
            events=["user.created", "user.updated"],
            secret="super-secret",
            headers={"X-App": "my-service"},
        )
    ],
)

router = CRUDRouter(..., webhooks=webhooks)

Event names look like: modelname.created, modelname.updated, modelname.deleted, modelname.restored.

9. Import and export

  • Export: GET /{prefix}/export?fmt=csv|xlsx
  • Import: POST /{prefix}/import with a CSV/XLSX file

Disable them if you do not need them:

router = CRUDRouter(..., disable=["import", "export"])

10. Bulk create

  • Endpoint: POST /{prefix}/bulk
  • Payload: list of create schema objects

Disable if not needed:

router = CRUDRouter(..., disable=["bulk"])

11. Global exception handling

from fastapi_crud_engine.core.handlers import register_exception_handlers

register_exception_handlers(app)

This handles library exceptions consistently (not found, permission denied, lock conflict, rate limit, bulk errors).

12. Using repository directly

from fastapi_crud_engine.repository import CRUDRepository

repo = CRUDRepository(User, soft_delete=True)

# Inside your service/endpoint:
# obj = await repo.create(db, {"email": "a@b.com"})
# page = await repo.list(db, params=PageParams(page=1, size=20), filter_params=request.query_params)

Configuration

Common router options

  • soft_delete=True
  • audit_trail=True
  • filterset=FilterSet(...)
  • cache=Cache(...)
  • rate_limit=RateLimiter(...)
  • webhooks=WebhookConfig(...)
  • hooks=CRUDHooks(...)
  • field_permissions=FieldPermissions(...)
  • disable=["import", "bulk", "export", "deleted", "restore"]

Environment variables

  • REDIS_URL
    • Used by Cache(backend="auto") and RateLimiter(redis_url=None)
  • CELERY_BROKER_URL
    • Used when WebhookConfig(delivery="celery")

Contributing

  • Read CONTRIBUTING.md
  • Create a branch from main
  • Add tests for any behavior change
  • Open a pull request with clear scope and rationale

License

MIT License. See LICENSE.

Acknowledgements

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_crud_engine-0.1.3.tar.gz (39.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_crud_engine-0.1.3-py3-none-any.whl (30.5 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_crud_engine-0.1.3.tar.gz.

File metadata

  • Download URL: fastapi_crud_engine-0.1.3.tar.gz
  • Upload date:
  • Size: 39.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for fastapi_crud_engine-0.1.3.tar.gz
Algorithm Hash digest
SHA256 78466c7426e8ce6c7c73119dcfcb4f861f7b4183c20937ad38247afba49f2a5a
MD5 4614f8cac89255535b0c987b30859d87
BLAKE2b-256 fa793d50a7cfc68a30cec00d845bfbeb462955032b1951fb97947abe34df9bb9

See more details on using hashes here.

File details

Details for the file fastapi_crud_engine-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_crud_engine-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 0344d7cad598a373d8b00e0bf3f280bc3bfd2f6e6a7691d9c4eebbec474cc8c8
MD5 525d0f3440a14ebe06f3ba87f35ea434
BLAKE2b-256 f5070786b232bb8e1edee209e27286ea52b4b2f2c9bd6db71e0eaacb45472c33

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page