Skip to content

Part 2 · The Frontend — Astro on Rust

A backend with no face is a curl demo. In Part 2, quill gets a real Astro frontend — the same framework these books are built with — talking to your Rust API. The interesting engineering here isn’t the HTML; it’s the contract between a JavaScript frontend and a Rust backend, and the two hard things every full-stack app must solve: who is this user, and how do I stream a response as it’s being produced.

┌────────────────────┐ fetch (build + runtime) ┌──────────────────────┐
│ Astro frontend │ ─────────────────────────► │ quill · Rust backend │
│ · post list (SSG) │ │ · /api/posts │
│ · post page (SSR) │ ◄───────────────────────── │ · /api/auth/session │
│ · editor (client) │ JSON + SSE │ · /api/*/stream │
└────────────────────┘ └──────────────────────┘
  • A reader site: the post list and each post, rendered from the Rust API — static where it can be, server-rendered where it must be fresh.
  • An editor: a real form that creates and updates posts through the API.
  • Sessions: signed cookies so the editor knows who you are, verified on the Rust side.
  • Server-Sent Events: a streaming endpoint the frontend can consume token-by-token — built now, because Part 3’s AI drafting rides on exactly this pipe.
ConcernWhere it livesWhy
Content renderingAstro (SSG/SSR)ship HTML, hydrate only what’s interactive
Data & authRust (axum)one source of truth, typed, fast, secure
The contractJSON + SSE over HTTPlanguage-agnostic, cache-friendly, streamable

The lesson that transfers everywhere: keep the frontend dumb and the backend authoritative. The Rust service owns data, identity, and business rules; Astro owns presentation. This is the same split you’d draw for a mobile app, a CLI, or a third-party integration hitting the same API.

ChTitleYou addThe idea it teaches
1The contractAstro app, typed API client, CORSSSG vs SSR against a live API, sharing a schema
2The editorcreate/update forms → APIforms, optimistic UI, error surfaces
3Sessionssigned-cookie auth, /sessioncookies, CSRF basics, auth as middleware in axum
4Streamingan SSE endpoint + consumertext/event-stream, backpressure, the AI-ready pipe

Once it compiles, what does it take to run for real users? Part 2’s answer: a trust boundary. The moment a browser can talk to your service, every request is untrusted input. You’ll see how Rust’s type system and axum’s extractors turn “parse, don’t validate” into the default, and how the same Send/Sync discipline from async Rust makes a streaming endpoint safe under many simultaneous readers.

Next: Part 3 · AI Content Generation →