Route Templates¶
AutoCRUD generates FastAPI endpoints by applying a set of route templates to each registered resource.
A route template is a small unit of endpoint generation logic:
- It defines one “slice” of the API (e.g. create, list, read, update, patch, delete, switch, export/import…).
- It is applied per model to a router/app.
- Multiple templates compose into a complete CRUD surface.
What is a RouteTemplate?¶
A route template implements the IRouteTemplate interface:
apply(model_name, resource_manager, router): registers one or more FastAPI routes.order: controls the application order across templates.
class IRouteTemplate(ABC):
"""Route template interface: defines how to generate one set of API routes."""
@abstractmethod
def apply(
self,
model_name: str,
resource_manager: IResourceManager[T],
router: APIRouter,
) -> None:
"""Apply this template to the given model and router."""
...
@property
@abstractmethod
def order(self) -> int:
"""Ordering weight for route template sorting."""
...
AutoCRUD provides a shared base class BaseRouteTemplate:
- Accepts a
DependencyProviderto inject consistent dependencies (e.g. current user, current time). - Implements comparable ordering so templates can be sorted.
class BaseRouteTemplate(IRouteTemplate):
def __init__(
self,
dependency_provider: DependencyProvider = None,
order: int = 100,
):
self.deps = dependency_provider or DependencyProvider()
self._order = order
@property
def order(self) -> int:
return self._order
def __lt__(self, other: IRouteTemplate):
return self.order < other.order
def __le__(self, other: IRouteTemplate):
return self.order <= other.order
DependencyProvider¶
Route templates typically need shared request-scoped inputs like:
current_usercurrent_time
AutoCRUD centralizes those as injectable FastAPI dependencies via DependencyProvider.
Default behavior (when not customized):
get_user()→"anonymous"get_now()→datetime.now()
class DependencyProvider:
"""Provides dependency callables for user/time."""
def __init__(self, get_user: Callable = None, get_now: Callable = None):
self.get_user = get_user or self._create_default_user_dependency()
self.get_now = get_now or self._create_default_now_dependency()
def _create_default_user_dependency(self) -> Callable:
def default_get_user() -> str:
return "anonymous"
return default_get_user
def _create_default_now_dependency(self) -> Callable:
def default_get_now() -> dt.datetime:
return dt.datetime.now()
return default_get_now
This makes templates reusable and consistent across apps, while still allowing users to override auth/time logic centrally.
How AutoCRUD applies route templates¶
AutoCRUD holds:
resource_managers:{resource_name -> ResourceManager}route_templates: list ofIRouteTemplate
When you call:
AutoCRUD will:
- Validate
Reftargets (warn on dangling refs) - Install referential integrity handlers
- Sort templates by
order - Apply each template to each model (best-effort)
- Register custom create-action routes
- Register custom update-action routes
- Register ref-specific routes (referrers + relationships)
- Register global backup / restore routes
Key portion (simplified):
self.route_templates.sort()
for model_name, resource_manager in self.resource_managers.items():
for route_template in self.route_templates:
try:
route_template.apply(model_name, resource_manager, router)
except Exception:
pass
Important note: template application is intentionally best-effort. A failing template will be skipped so that unrelated routes can still be generated.
Default templates¶
If you do not pass route_templates explicitly, AutoCRUD builds a default list:
[
CreateRouteTemplate,
ListRouteTemplate,
ReadRouteTemplate,
UpdateRouteTemplate,
PatchRouteTemplate,
SwitchRevisionRouteTemplate,
RerunRouteTemplate,
DeleteRouteTemplate,
PermanentlyDeleteRouteTemplate,
RestoreRouteTemplate,
BatchDeleteRouteTemplate,
BatchRestoreRouteTemplate,
ExportRouteTemplate,
ImportRouteTemplate,
]
You can also pass a dict {TemplateClass: kwargs} to configure defaults while still using the standard set.
Canonical endpoints generated by key templates¶
Below are the canonical endpoints (new “bare path” endpoints) used going forward.
Deprecated aliases may exist (e.g. /data, /meta, /full), but should not be considered the primary API surface.
ListRouteTemplate (List resources)¶
GET /{model_name}
- Canonical listing endpoint.
- Supports
returnsto control response sections per item. - Supports standard filtering/sorting (including
qb).
Example (from template):
GET /usersGET /users?returns=dataGET /users?limit=20&offset=40
ReadRouteTemplate (Read single resource)¶
GET /{model_name}/{resource_id}
- Canonical read endpoint.
- Supports
returns=data,revision_info,meta. - Supports
revision_idandpartial/partial[].
Example:
GET /users/123GET /users/123?returns=metaGET /users/123?revision_id=users:123:2
CreateRouteTemplate (Create)¶
POST /{model_name}
Creates a new resource and returns RevisionInfo.
UpdateRouteTemplate (Update / Modify)¶
PUT /{model_name}/{resource_id}
mode=update(default): creates a new revision (append)mode=modify: updates the current revision in-place (no new revision)- optional
change_statusonly whenmode=modify
PatchRouteTemplate (JSON Patch / Modify)¶
PATCH /{model_name}/{resource_id}
- RFC 6902 JSON Patch support
mode=update(default): new revisionmode=modify: in-place update of current revision
SwitchRevisionRouteTemplate (Switch current revision)¶
POST /{model_name}/{resource_id}/switch/{revision_id}
Switches the resource’s current revision pointer to a specific revision.
Notes:
- Does not create a new revision.
- Revision history is preserved.
- Similar to moving a “HEAD pointer” in a version graph.
RerunRouteTemplate (Job rerun; only when message queue exists)¶
POST /{model_name}/{resource_id}/rerun
Registered only when:
resource_manager.message_queue is not None
Behavior:
- Only allows rerun when job status is
completedorfailed - Resets job to
pending, clears retries/errmsg, enqueues again
ExportRouteTemplate / ImportRouteTemplate (Per-model backup)¶
GET /{model_name}/export→ streaming.acbakPOST /{model_name}/import→ import.acbak(supportson_duplicate)
Export supports the same query parameters as search/list (e.g. qb, is_deleted, time ranges) to filter what is included.
Custom templates¶
You can extend AutoCRUD by providing your own IRouteTemplate implementation:
- Add completely new endpoints
- Add “derived views” (e.g.
/search,/stats,/summary) - Change behaviors by replacing default templates with custom ones
Recommended pattern:
- Keep each template focused on one area (1 file, 1 concern)
- Use
DependencyProviderso auth/time logic is consistent - Choose
ordercarefully to avoid route conflicts
Design rationale (why templates?)¶
Route templates exist to keep AutoCRUD:
- Composable: add/remove route families without rewriting everything
- Extensible: users can ship custom endpoints as templates
- Testable: each template can be tested in isolation
- Consistent: shared dependencies and response patterns across endpoints
This architecture is what allows AutoCRUD to grow beyond “CRUD” into:
- versioning primitives (switch)
- job workflows (rerun)
- migration and schema evolution
- bulk operations and backup/restore
- reference graph utilities (ref routes)