diff --git a/docs/comptime-endpoint-inventory.md b/docs/comptime-endpoint-inventory.md new file mode 100644 index 0000000..82c67e5 --- /dev/null +++ b/docs/comptime-endpoint-inventory.md @@ -0,0 +1,115 @@ +> adopted from the notes repo during the 2026-08-23 curation pass; project design/retro content lives with its project. + +# Comptime endpoint inventories + +> written against zig 0.16. + +The API reference in [ZDS](https://tangled.org/zat.dev/zds) (our zig PDS) is +not reflection in the usual runtime sense. It is a comptime-known data +inventory. + +In Zig, top-level `const` arrays of structs are available to any importing +module at compile time and runtime. If the fields are string literals, enum +values, and slices of string literals, the compiler can type-check the whole +inventory without needing a registry object or AST parser. + +For ZDS, each endpoint is a struct with fields like: + +```zig +pub const Endpoint = struct { + route: Route, + method: []const u8, + path: []const u8, + group: []const u8, + auth: []const u8, + summary: []const u8, + params: []const []const u8 = &.{}, + body: []const []const u8 = &.{}, + response: []const []const u8 = &.{}, + notes: []const u8 = "", +}; +``` + +Then: + +- routing loops over `endpoints` +- docs rendering loops over `endpoints` +- OpenAPI export loops over `endpoints` +- tests assert that important method/path pairs map to the intended route enum + +This is compile-time friendly, but not magic. We are manually declaring a table +that is more structured than comments and less ambitious than a full router DSL. + +## Why not AST parsing + +AST parsing would let documentation be inferred from calls like +`router.get("/xrpc/...", handler, ...)`, but it would also bind the docs system +to source syntax rather than program structure. That tends to be brittle in Zig +because route registration can be hidden behind helper functions, `inline for`, +comptime parameters, or imported modules. + +The current inventory is boring, but boring is valuable: + +- the compiler checks field names and route enum values +- code search finds every route declaration +- docs do not depend on a separate source parser +- metadata can grow naturally + +## How this could get better + +The next improvement is probably not runtime reflection. It is a stronger +comptime registration shape. + +Possible direction: + +```zig +const routes = api_reference.routes(.{ + .{ .GET, "/api", .api_docs, .{ .group = "zds", .summary = "..." } }, + .{ .POST, "/xrpc/com.atproto.repo.createRecord", .repo_create_record, .{ + .group = "repo", + .auth = "bearer", + .lexicon = "com.atproto.repo.createRecord", + } }, +}); +``` + +The helper could validate at comptime that: + +- methods are from a known method enum +- XRPC paths contain valid NSIDs +- route enum values are unique where required +- HEAD and GET pairings are intentional +- lexicon IDs match path NSIDs + +Zig tools that matter here: + +- `comptime` parameters for route DSL helpers +- `inline for` over tuple literals or arrays +- `@typeInfo` if we later want to inspect handler signatures or schema structs +- `@hasDecl` for optional module-provided metadata +- `std.meta` helpers for enum and struct introspection + +## httpz and route metadata + +Karl's `httpz` has a real router with method trees, path params, groups, route +configuration, middleware, and custom dispatch. It does not expose a public +documentation registry in the pinned version used by ZDS. + +That means ZDS has two reasonable options: + +- keep its own endpoint inventory and dispatch switch, as it does now +- wrap `httpz` route registration with a ZDS-owned registration helper that + records metadata and registers the route at the same time + +The second option is attractive if ZDS later moves from its current route enum +switch to direct `httpz` actions. For now, the explicit inventory is a good +middle ground. + +## HTMX + +HTMX is attractive when the server owns small HTML fragments and the UI needs +stateful server interactions: endpoint try-it forms, authenticated request +probes, schema expansion, saved examples, or live health checks. + +For plain search, group filtering, and clipboard copy, vanilla JavaScript is +lighter and keeps the reference page deployable as one rendered HTML document.