blog — the smallest whole thing
In this repository: example/blog/
Three tables, everything codegen emits from them, the pieces that had to be written by hand, and an assembled server. It is a real test suite rather than a listing, so it cannot drift from the code.
Your first app walks it line by line. This page is the summary.
What it proves
Section titled “What it proves”That the generated half and the hand-written half compose. The soft delete
is the case: schema.SoftDelete() adds a deleted_at column and stops, so
making it mean something is a BeforeQuery hook that adds the predicate and a
hand-written DELETE /posts/{id} that stamps the column. Both are a few lines,
both are visible, and they mount onto the same Huma API in two calls rather than
through a wrapper.
That capabilities are decisions. body is searchable but not sortable.
view_count is read-only but still filterable and sortable, so “most read this
week” is a URL and no request can set the number. password_hash is hidden and
deliberately not filterable, because a filterable secret can be recovered by
probing.
That a resource can refuse to mount. posts declares SoftDelete, so
registration fails until something filters the column. The test suite has to
register the hook before it can build a server, which is the check working.
The shape
Section titled “The shape”blogschema/schema.go three tables — the source of truth an author edits │ ├─▶ models_gen.go row structs ├─▶ columns_gen.go typed column facade ├─▶ rest_gen.go request bodies + Register └─▶ sqlb.json the manifest
hooks.go the soft-delete predicatepost_ext.go AddViewCount — the generator cannot produce itdeletes.go DELETE /posts/{id} as an UPDATEserver_test.go the assembled server, and every claim assertedRead it for
Section titled “Read it for”blogschema/schema.go |
Four kinds of capability decision, with a comment on each that is not obvious |
hooks.go |
Eleven lines that constrain every read of a model |
deletes.go |
Why a hook cannot turn a DELETE into an UPDATE, and what to do instead |
post_ext.go |
Incrementing a counter in the database rather than read-modify-write |
server_test.go |
The assembled chi + Huma + generated Register server |
What it is not
Section titled “What it is not”There is no authentication, so it does not scope by tenant — though its tests
show the shape, and it is one more predicate on the same hook. It runs against
an in-memory database/sql driver rather than a container, which keeps it in
the fast inner loop: it is proving what codegen emits and how the pieces
assemble, not what Postgres does under concurrency. For that, read
library or exchange.
- Your first app — the walkthrough
- tasks — the same machinery once an application has a real shape