Auto-generate FastAPI CRUD endpoints from SQLModel models
Project description
auen
Auto-generate FastAPI CRUD endpoints from SQLModel models.
Installation
pip install auen
Quickstart
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from fastapi import FastAPI
from sqlalchemy.ext.asyncio import create_async_engine
from sqlmodel import Field, SQLModel
from sqlmodel.ext.asyncio.session import AsyncSession
from auen import CrudRouterBuilder
engine = create_async_engine("sqlite+aiosqlite:///heroes.db")
class Hero(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
name: str
secret_name: str
age: int | None = None
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
async with engine.begin() as conn:
await conn.run_sync(SQLModel.metadata.create_all)
yield
async def get_session() -> AsyncGenerator[AsyncSession, None]:
async with AsyncSession(engine) as session:
yield session
app = FastAPI(lifespan=lifespan)
app.include_router(CrudRouterBuilder.for_model(Hero, get_session).build())
This gives you:
| Method | Path | Description |
|---|---|---|
| POST | /heros/ |
Create a hero |
| GET | /heros/ |
List heroes |
| GET | /heros/{id} |
Get a hero |
| PATCH | /heros/{id} |
Update a hero |
| DELETE | /heros/{id} |
Delete a hero |
Explicit Schemas (Recommended)
For production, define explicit schemas instead of auto-derived ones:
from pydantic import BaseModel
from auen import CrudRouterBuilder, SchemaConfig
class HeroCreate(BaseModel):
name: str
secret_name: str
age: int | None = None
class HeroRead(BaseModel):
id: int
name: str
secret_name: str
age: int | None = None
class HeroUpdate(BaseModel):
name: str | None = None
secret_name: str | None = None
age: int | None = None
app.include_router(
CrudRouterBuilder.for_model(Hero, get_session)
.with_schemas(
SchemaConfig(
create=HeroCreate,
read=HeroRead,
update=HeroUpdate,
)
)
.build()
)
Authentication
from fastapi import Header, HTTPException
from auen import AuthConfig, CrudRouterBuilder
def get_current_user(authorization: str = Header()) -> str:
if not authorization.startswith("Bearer "):
raise HTTPException(status_code=401)
return authorization[7:] # return user identity
app.include_router(
CrudRouterBuilder.for_model(Hero, get_session)
.with_auth(AuthConfig(dependency=get_current_user))
.build()
)
Row-Level Policies
from auen import AuthConfig, CrudRouterBuilder
class OwnerPolicy:
def can_create(self, user, obj_in):
return True
def can_read(self, user, db_obj):
return db_obj.owner_id == user
def can_update(self, user, db_obj, obj_in):
return db_obj.owner_id == user
def can_delete(self, user, db_obj):
return db_obj.owner_id == user
def filter_list_query(self, user, query):
return query.where(Hero.owner_id == user)
app.include_router(
CrudRouterBuilder.for_model(Hero, get_session)
.with_auth(AuthConfig(dependency=get_current_user))
.with_policy(OwnerPolicy())
.build()
)
Lifecycle Hooks
from auen import CrudRouterBuilder, HooksConfig
async def send_welcome_email(session, user_obj, current_user):
... # send email, log event, publish to queue, etc.
async def validate_before_create(session, obj_in, current_user):
... # raise HTTPException to abort
app.include_router(
CrudRouterBuilder.for_model(Hero, get_session)
.with_hooks(
HooksConfig(
before_create=validate_before_create,
after_create=send_welcome_email,
)
)
.build()
)
Pagination & Filtering
from auen import CrudRouterBuilder, PaginationConfig, FilterConfig, FilterFieldConfig
app.include_router(
CrudRouterBuilder.for_model(Hero, get_session)
.with_pagination(PaginationConfig(default_limit=20, max_limit=100))
.with_filters(
FilterConfig(
fields={"name": FilterFieldConfig(ops=frozenset({"eq"}))},
sort_fields=["name", "age"],
)
)
.build()
)
Selecting Operations
from auen import CrudRouterBuilder, Operation
app.include_router(
CrudRouterBuilder.for_model(Hero, get_session)
.with_operations({Operation.LIST, Operation.READ}) # read-only API
.build()
)
Development
# Install dependencies
uv sync
# Run tests
uv run pytest
# Format
uv run ruff format .
# Lint
uv run ruff check .
# Type check
uv run ty check
License
MIT
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
auen-0.2.0.tar.gz
(112.9 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
auen-0.2.0-py3-none-any.whl
(19.8 kB
view details)
File details
Details for the file auen-0.2.0.tar.gz.
File metadata
- Download URL: auen-0.2.0.tar.gz
- Upload date:
- Size: 112.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82b3100c7b89dedcca3b9cf65fe4ac3b86260110cf5e11caa9297b3ed699ae92
|
|
| MD5 |
2472d95e80ffbc16be374d56a1ba8ffb
|
|
| BLAKE2b-256 |
3c6ec2de41bf854f3bcd87f42fe1eadb52ae85d03c865affbb1ac12709d49193
|
File details
Details for the file auen-0.2.0-py3-none-any.whl.
File metadata
- Download URL: auen-0.2.0-py3-none-any.whl
- Upload date:
- Size: 19.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.4 {"installer":{"name":"uv","version":"0.10.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5d7880d966bea0b0a2193fb8af7947c3d7c9c2a15153bca15a179ab45aea86a
|
|
| MD5 |
b615634b0d26061eefd4a6f7f129cd2f
|
|
| BLAKE2b-256 |
577702e7ca407a14f24b1b7f1cf835d69b60da55cdb038d6fe3e9b5feabfa38f
|