Resources
Schema → Resource() → ResourceConfig and the CRUD exec pipeline.
Source: resource.go, types.go.
Schema
type Schema[Row, Response, CreateBody, UpdateBody, ListInput any] struct {
Fields schema.Fields
Operations schema.Operations
PK *schema.PK
Guards []Guard[map[string]any] // uniform, all ops
Access Access // per-op slots
Hooks Hooks[map[string]any, map[string]any]
LookupField string // Get/Update/Delete addressing
AutoCreate bool // retained but IGNORED
}Resource() freezes this into a ResourceConfig:
func Resource[Row, Response, CreateBody, UpdateBody, ListInput any](
name, table string,
s Schema[Row, Response, CreateBody, UpdateBody, ListInput],
) ResourceConfignamedrives routes (/api/{name},/api/{name}/{id}) and OpenAPI tags;tabledefaults toname.Modelis(*Row)(nil)— used for reflection (map models take theListMappath).registerRoutesFnis unexported: the generic type parameters survive into the Huma handlers, and app code cannot replace them.
Operations.Enabled("get"|"list"|"create"|"update"|"delete") — nil/empty means enabled; the DSL can deny-map or allow-list ops.
Routes
| Method | Path | Operation |
|---|---|---|
GET | /api/{name} | list |
GET | /api/{name}/{id} | get |
POST | /api/{name} | create |
PATCH | /api/{name}/{id} | update |
DELETE | /api/{name}/{id} | delete |
Huma unwraps the Body field, so the OpenAPI schema reflects the inner type directly. Shapes are frozen by the OpenAPI snapshot — do not rename GetInput, CreateInput[B], UpdateInput[B], DeleteInput, or the *Output[R] wrappers.
GetInputcarriespath:idplus an accepted-but-ignoredquery:expandkept for OpenAPI stability.ListInputmust implementListInputer.ToListOptions() db.ListOptions— generated by codegen.- All lists return
ListResponse[T]{Data, Total, Page, Limit}(types.go), echoing the effective page/limit after clamping.
LookupField overrides PK addressing (LookupField || PK.Column || "id") — e.g. Frappe tables addressed by name.
Exec order (every op)
Guard.Check → strip unknown/readonly/PK → from: injection → defaults
→ timestamps → validation → Guard.Filter pushdown → single-query txstripUnknownKeysdrops keys not in the schema (mass-assignment guard).- Readonly fields are stripped on write; the PK column is stripped on create (except
AutonamePrompt, the only client-supplied PK) and the lookup column is never updatable. created_at/updated_atare stamped only when the schema declares them. Frappe tables usecreation/modifiedvia app hooks — Brick never invents columns there.- Unique violations surface as
409by SQLSTATE23505inspection, never string matching; races that slip past the in-tx precheck still map to409. - Out-of-scope reads/updates/deletes are
404, not403(no existence oracle).
Empty update bodies are rejected with 400 nothing to update. Unknown or non-sortable sort values are 400.