Two OpenAPI 3.1 documents are published with this site. Neither is written by hand: both are
generated from the routers and handlers by webdoc/scripts/gen-openapi.mjs, and CI fails if
either is behind the source it was derived from.
queen-broker.json
The broker's HTTP API: the message plane, queue and consumer-group management, inspection, status and operator surfaces.
queen-proxy.json
The proxy's own surface: service endpoints, the login and OAuth flow, and the cluster console API.
| Document | Operations | Paths | Request bodies derived from a type | Request bodies opaque |
|---|---|---|---|---|
queen-broker.json |
93 | 82 | 16 | 14 |
queen-proxy.json |
21 | 17 | 0 | 0 |
What is derived, and from what
Every element below is read out of a specific construct in the Rust source. If the code changes, the document changes with it.
| Element | Derived from |
|---|---|
| Paths and methods | the Router::new() chain: the broker’s in server/src/main.rs, the proxy’s in proxy/src/main.rs plus the nested console and auth routers |
| Path parameters | the :name segments of the registered path |
| Query parameters | the handler’s Query<T> extractor: the fields of T with their serde renames and optionality. For a handler taking Query<HashMap<..>>, the literal keys it reads out of the map, through that extractor’s own binding name |
| Request bodies | the struct the handler passes to serde_json::from_slice, walked recursively into nested structs. Required unless the handler branches on an empty body, in which case the body is optional |
| Response status codes | every StatusCode variant reachable in the handler body |
| Authorization | auth::route_access_level, which also fills x-queen-access-level |
| Tenant scoping | whether the handler takes the Tenant request extension, which also adds the x-queen-tenant header parameter |
What is not derivable, and how the documents say so
Two things resist derivation, and the documents mark them rather than guess.
Success response bodies. The hot paths assemble their JSON by string concatenation
(render_push_results, render_pop_parts, render_ack_results), and several management
routes forward a stored procedure’s JSON verbatim. There is no type to read. Those responses
carry "x-queen-schema": "opaque" and an unconstrained schema, deliberately not
type: object, because some of these routes answer with a top-level array and asserting
“object” would be worse than asserting nothing. The field-by-field contract lives on the route
pages under the HTTP reference.
Query parameters that are forwarded whole. Some listing handlers hand their entire query
map to a stored procedure without reading keys by name in Rust. Those operations carry
"x-queen-query-params": "forwarded" and a note; their parameters are documented on the route
pages.
Request bodies that a handler parses as a dynamic JSON document, rather than into a struct,
carry "x-queen-schema": "opaque" too, with the keys the handler does read by name listed as
properties. The KV and timer routes are the largest group in that state: their handlers read the
body as a dynamic document and forward it to a stored procedure, which is where the shape rules
live, so their operations describe the request as an open object and the field-by-field contract
is on kv and timers. A schema derived from those
handlers would describe the JavaScript-visible surface of the parser rather than the contract.
A route that refuses query strings. The KV path routes take a query map only to reject a
non-empty one, which is a privacy boundary rather than a parsing habit. They carry
"x-queen-query-params": "rejected" and a note saying so, because publishing them as forwarded
would say the opposite of the truth about exactly the routes where the rule matters.
Extensions
Both documents use a small set of x-queen-* extensions so a reader or a tool can tell
derived facts from undeclared ones.
| Extension | Meaning |
|---|---|
x-queen-access-level |
public, read-only, read-write, write-only or admin, from the broker’s authorization table |
x-queen-tenant-scoped |
the handler resolves a tenant, so the request is scoped when QUEEN_TENANCY_HEADER is on |
x-queen-handler |
the file and function that serves the operation |
x-queen-schema |
derived when the schema comes from a Rust type, opaque when it could not |
x-queen-query-params |
typed, adhoc, forwarded, rejected or none: how the query parameters were recovered, or that the route refuses them |
x-queen-catch-all |
the path is an axum catch-all segment, which OpenAPI cannot express |
x-queen-note |
a caveat about this operation specifically |
Using them
Both files are static assets, so any tool that reads a URL can consume them:
curl -s https://queenmq.com/openapi/queen-broker.json -o queen-broker.jsonGenerating a client is a reasonable use for the request side: paths, parameters and bodies
are all derived. Be careful with generated response types: wherever
x-queen-schema is opaque, the generator will produce an untyped value, and the real shape
is the one documented on the route page.
The broker document describes every route the router declares, and for the data plane that is
also every route a broker answers: the router is not conditional, so the eight KV and timer
operations and the eight ephemeral-queue operations are registered on every cell and a client
generated from this document finds them there.
What configuration still changes is the verdict a route gives, not its existence, so a generated
method can meet a 403 from a quota or a 503 from an operator’s kill switch.
Regenerating
pnpm --dir webdoc genpnpm --dir webdoc gen:check is the CI form: it regenerates into memory and fails if what is
committed differs. The generator also runs a structural self-check on both documents before
writing them. Duplicate operation ids, undeclared path parameters, dangling $refs and
Rust-style :param leftovers all fail the build rather than ship.