Build a posts feature end to end
From hello to a running apps/blog binary — HTTP CRUD behind the guards, validation, Postgres, and an e2e test, one runnable page at a time.
You ship one feature — posts — into the Publish story’s
blog app: entity, service, a PostsController behind the guards,
validation, Postgres, and an e2e test. Each page leaves you with code that
compiles and a command you can run.
Pages 1–7 build your blog. Pages 8 and 9 read the reference api. That
is a deliberate switch, and worth knowing before you reach it: blog’s Post
has an id, a title and a body — no tenant column, no relation — because a small
domain is what makes pages 2 to 7 short. Per-caller row filtering and an
auto-resolved GraphQL relation both need a domain that has those things, so the
last two pages walk through the feature that does (api’s users) rather than
first sending you to add a column you have no use for. You still finish each
one with something to do in your own blog.
What you end up with
Section titled “What you end up with”hello for the quick-start binary, apps/blog/ for the tutorial app, a
posts/ feature with HTTP only, and the three auth roots nestrs g auth
writes on page 4 — a DB-backed route is guarded from its first request.
Directoryapps/blog/
- Cargo.toml
Directorysrc/
- main.rs
- module.rs
Directorytests/
Directorye2e/
- main.rs
Directorycrates/
Directoryfeatures/
Directorysrc/
Directoryidentity/
- …
Directoryauthn/
- …
Directoryauthz/
- …
Directoryposts/
- entity.rs
- service.rs
- module.rs
- mod.rs
Directoryhttp/
- controller.rs
- module.rs
- mod.rs
Two curls against the running binary, carrying the development token
POST /auth/dev-token mints on
Persist through Postgres. The bearer is not optional:
Repo filters every read by the caller’s ability, so the guards go on with
the database, not later.
$ curl -s -X POST http://localhost:3005/posts -H "Authorization: Bearer $TOKEN" \ -H 'Content-Type: application/json' \ -d '{"title":"Hello","body":"World"}'{"id":"018f…","title":"Hello","body":"World"}
$ curl -s http://localhost:3005/posts/018f… -H "Authorization: Bearer $TOKEN"{"id":"018f…","title":"Hello","body":"World"}And a passing e2e suite:
$ nestrs run test e2e PASS [ …] blog::e2e posts_round_tripWhat you should know going in
Section titled “What you should know going in”- A workspace scaffolded per Getting started —
the
nestrsCLI installed andnestrs run dev helloservingHello Worldfromcrates/features/src/hello/. - Rust 1.97+, and enough of Fundamentals, Configuration, and HTTP that module, provider, and controller are familiar terms.
- Docker available — the database and testing pages need Postgres
(
nestrs run db up); earlier pages run without one. - Page 1 adds
apps/blog/withnestrs new blog; everything after that happens inblog, nothello.
The pages, in order
Section titled “The pages, in order”Going further
Section titled “Going further”- Scaffold the app — the next step: add
apps/blog/withnestrs new blog. - Publish — the reference workspace this tutorial builds toward.
- Getting started — the workspace setup this tutorial assumes.