crudcrate
Every Sea-ORM entity needs the same handful of handler functions, request structs,
response structs, filter parsing, and pagination logic. crudcrate derives all of
it from your model definition — on Axum.
// Mount it:
let app = new.nest;
Security: the generated router is unauthenticated and has no default request body size limit. Before shipping, you MUST (1) add an Axum authentication middleware and (2) set
DefaultBodyLimiton the router — without the body-size cap, a singlePOST /batchrequest can exhaust server memory. Seedocs/src/advanced/security.mdand thescoped_accessexample.
This generates Customer, CustomerCreate, CustomerUpdate, and CustomerList
structs, a full CRUDResource implementation, and an Axum router with:
| Endpoint | Description |
|---|---|
GET /customers |
List with filtering, sorting, fulltext search, pagination |
GET /customers/{id} |
Single resource with relationship loading |
POST /customers |
Create |
PUT /customers/{id} |
Partial update |
DELETE /customers/{id} |
Delete |
POST /customers/batch |
Batch create |
PATCH /customers/batch |
Batch update |
DELETE /customers/batch |
Batch delete (with optional ?partial=true) |
What gets generated
From the entity above, EntityToModels produces:
// Plus: CRUDResource impl, Axum router, OpenAPI schemas
Option<Option<T>> in update structs distinguishes "not provided" (None) from
"set to null" (Some(None)).
See it work
List with pagination (range header):
|
Create:
|
Filter and search:
|
How it compares
For a single entity with filtering, sorting, pagination, and batch operations:
| Manual | crudcrate | |
|---|---|---|
| Entity definition | ~25 lines | ~25 lines |
| Request/response structs | ~60 lines | generated |
| Handler functions | ~120 lines | generated |
| Filter/sort/pagination | ~100 lines (shared) | built-in |
| Router wiring | ~10 lines | generated |
| Total per entity | ~200+ lines | ~25 lines |
Based on comparison with production APIs using Sea-ORM + Axum.
Install
By default this enables SQLite + derive macros. For PostgreSQL or MySQL:
= { = "0.7", = false, = ["postgresql", "derive"] }
Documentation
crudcrate.evanjt.com — Tutorials, walkthroughs, and reference.
docs.rs/crudcrate — API reference and attribute documentation.
The tutorials walk through everything from a minimal setup to hook-based customization, relationship loading, and production deployment.
Highlights
Hooks — Inject logic at any stage of any operation. Pre-validate, override the body, transform results, or run side effects after completion.
Relationships — Load nested data automatically. Batch-loaded at depth 1 (2 queries instead of N+1), recursive up to depth 5.
pub vehicles: ,
Filtering & Search — Rich query API generated from field attributes.
GET /customers?filter={"name_like":"John","email_neq":"spam@example.com"}
GET /customers?q=urgent&sort=["name","ASC"]&range=[0,24]
Field control — Decide exactly what appears in each generated model.
// auto-managed timestamp
// heavy field, detail view only
// internal, never exposed
Examples
Security caveats
The optional mysql feature pulls in sqlx-mysql, which depends on rsa 0.9.10. That version is affected by RUSTSEC-2023-0071 (the Marvin attack — a server-side timing side-channel against RSA decryption). There is no upstream fix yet.
The feature is opt-in. If you are not connecting to MySQL, leave it disabled. If you are, terminate the MySQL connection over a private network or unix socket rather than across a network-attacker-reachable path.
License
MIT