the http api reference
/docs has a second tab, http api. It lists every endpoint of the server: what it takes, what it returns, and the statuses with which it can fail. Two more endpoints serve the same content:
GET /api/openapi.jsonserves an OpenAPI 3.1 document.GET /api/referencerenders that document as a reference page, with a panel that sends requests.
The three agree because they come from one table: kayak_core::api_docs::endpoints(). The table is the routes. api_router is a fold over it (src/endpoints.rs). Thus an endpoint that is not in the table is never registered. handler_for matches on an Operation enum, so a table entry with no handler does not compile. route_of takes the method from the table. Thus you cannot document an endpoint as PUT and wire it to post(...).
You write this table by hand. It is not reflected. A Rust doc comment on an axum handler is not available at runtime, so there is nothing to reflect over. Thus the prose is in the table. Each handler has a one-line /// that points to its entry. This is the opposite of the rule for config structs. Write the description of an endpoint in its ApiDoc entry, not on the handler.
The bodies are an exception. Each body names a schema. api_docs::schemas() generates the schemas with schema_for!, the same reflection as the component reference. Thus the request and response shapes cannot drift from the Rust types.
src/openapi.rs renders the table as the document. The schemas are the only complex part. schemars 1.x emits JSON Schema 2020-12, which OpenAPI 3.1 embeds without change. Each generated schema is a root with its shared definitions in its own $defs. src/openapi.rs moves these definitions into one components/schemas and rewrites the $refs. The rest is json! literals.
Keep these three properties:
- The error body is a Rust type.
api_docs::ApiErrorexists so that the error schema in the document is generated.an_error_body_matches_the_documented_shapeintests/api.rsdeserializes a real failure into it. No other test connectsAppErrorto the document. /eventshas a limited description. OpenAPI can say that a response istext/event-stream. It cannot describe the events in the stream. That is the job of AsyncAPI. ThusBody::EventStreamrenders as a string body with prose. With a JSON body, clients try to parse the stream as one document.- The renderer is in the repository.
assets/scalar.jsis committed, and the page loads it from the server. Thusjust devworks without a network. The file is 3.5 MB.
To add an endpoint, change three places:
- Add an
Operationvariant inkayak-core/src/api_docs.rs. - Add an
ApiDocentry in the same file. - Add the handler arm in
src/endpoints.rs.
The compiler names two of them. The document, the /docs tab and the rendered reference follow without more changes.