Navigation
How OpenAPI and AsyncAPI contracts become browsable docs.printing press builds navigation from the API contract itself.
That means the sidebar, overview page, operation breadcrumbs, tag pages, model groups, and webhook section all come from
the same rendered documentation model. There is no second navigation file to keep in sync. The spec owns the shape, and
printing press turns that shape into stable pages.
For OpenAPI, the navigation model is composed from:
- root-level OpenAPI tags
- operation tags
- operation paths and operation IDs
- component models
- webhooks
- diagnostics counts, when diagnostics mode is enabled
For AsyncAPI, it is composed from operations, their send or receive action, channel and protocol context, and
the available AsyncAPI component types.
OpenAPI 3.2 hierarchical tags
OpenAPI 3.2 allows tags to describe hierarchy. printing press reads parent relationships from the root tags list
and builds a tree from them.
Use this when the API already has a product, domain, or workflow structure:
openapi: 3.2.0
info:
title: Travel API
version: 1.0.0
tags:
- name: Travel
summary: Travel
kind: nav
- name: Bookings
summary: Bookings
parent: Travel
description: Booking lifecycle operations.
- name: Payments
summary: Payments
parent: Travel
description: Payment capture and refund operations.
paths:
/bookings:
get:
tags:
- Bookings
summary: List bookings
operationId: listBookings
responses:
"200":
description: OK
In that shape, Travel is the parent navigation group. Bookings and Payments are child groups. Operations tagged
with Bookings appear under the Travel > Bookings path and get breadcrumbs back through that same hierarchy.
kind: nav marks a tag as a grouping node. Use it for a parent that exists to organize the docs, not to own operations
directly.
Each tag also gets its own generated tag page under tags/*.html. If the tag has a markdown description, that
description is rendered on the tag page before the operation list.
OpenAPI 3.1 flat tags
OpenAPI 3.1 tags are flat, and printing press treats them that way.
openapi: 3.1.0
info:
title: Travel API
version: 1.0.0
tags:
- name: Bookings
description: Booking lifecycle operations.
- name: Payments
description: Payment capture and refund operations.
paths:
/bookings:
get:
tags:
- Bookings
summary: List bookings
operationId: listBookings
responses:
"200":
description: OK
The root tags list defines the visible operation groups. Operations are assigned by tag name, so the value in
operation.tags should match the root tag name.
If a root tag is declared but never receives an operation or child tag, printing press removes it from the rendered
navigation. Empty placeholders do not clutter the docs.
AsyncAPI operations and protocols
AsyncAPI operation navigation groups operations by the protocol context resolved from servers, bindings and traits. Common protocols such as Kafka, AMQP, MQTT, NATS, Pulsar, Redis, SNS, SQS, Solace and WebSocket are rendered as named protocol groups.
Each operation link uses the summary when it exists, then falls back to operationId. The action appears separately:
← RCVmeans the application receives a messageSND →means the application sends a message
The operation page keeps the same direction next to the channel address. This makes inbound and outbound flow visible without turning a channel into an HTTP path or a message into a response.
AsyncAPI model navigation is generated from the component types present in the document, including schemas, messages, channels, parameters, security schemes, replies, reply addresses, correlation IDs, operation traits and message traits.
Slug matching and stable URLs
Every generated page gets a URL-safe slug.
Tag names, operation IDs, model names, and synthetic path groups are normalized into lower-case, kebab-case URL segments. Long slugs are bounded, and collisions get a numeric suffix so pages stay addressable.
Operations prefer operationId for their page slug:
operationId: listBookings
That becomes:
operations/list-bookings.html
If an OpenAPI operation has no operationId, printing press falls back to the HTTP method and path. AsyncAPI
operations fall back to their action and channel identity.
Stable operation IDs are the cleanest way to keep links durable across releases. Tag slugs and model slugs follow the same URL-safe rules, so generated links work in static, published, and served output.
Inside the rendered docs, those slugs become the matching key for navigation state. The current operation or model slug opens the right group, marks the active link, and connects breadcrumbs back to generated tag, operation, and model pages.
Path fallback
Some specs use no operation tags. Others use one or two broad tags across a large API, which makes the sidebar almost useless.
When tags are missing, unknown, or too coarse, printing press composes operation navigation from path patterns.
It reads the first meaningful path segments and turns them into navigation groups:
/v1/accounts/{accountId}/transactions
becomes:
Accounts > Transactions
Version prefixes like v1, path parameters like {accountId}, and action-only segments like get, list, create,
update, and delete are skipped so the navigation stays resource-focused.
When a path group has multiple useful second-level segments, printing press creates a parent and child structure. When
there is only one useful segment, it stays flat.
Coarse tag fallback
Large APIs sometimes tag every operation with the same vendor, product, or umbrella tag.
For that shape, printing press can treat the API as effectively untagged and reuse the same path-pattern grouping. By
default, this happens when a spec has enough operations and only a very small number of distinct operation tags.
So a large spec that tags everything as:
tags:
- name: plaid
paths:
/accounts:
get:
tags:
- plaid
/transactions:
get:
tags:
- plaid
can render as:
Accounts
Transactions
instead of one giant plaid bucket.
This is not a replacement for good tags. It is a safety net for specs that were authored for validation, not for docs.
Models and webhooks
Operation tags are only one part of the navigation.
printing press also builds a model section from contract components. OpenAPI schemas, responses, parameters, request
bodies, headers, security schemes, examples, links and callbacks are grouped by component type when they exist. AsyncAPI
uses the event-driven component groups described above.
Webhooks are rendered as their own navigation section, separate from request-response operations.
The result is one sidebar with:
- API overview
- diagnostics, when diagnostics mode is enabled
- operations
- models
- webhooks
Authoring guidance
Use OpenAPI 3.2 hierarchical tags when the API has a real information architecture.
Use OpenAPI 3.1 flat tags when the API is smaller, or when a single operation group is enough.
Keep root tag names and operation tag values identical. summary is a better place for a cleaner display label.
Prefer stable operationId values. They produce better operation page URLs than method-and-path fallback slugs.
For AsyncAPI, write concise operation summaries and stable operation IDs, and keep channel addresses focused on transport routing. The summary becomes the human label; the operation ID keeps generated links durable.
Let the path fallback clean up unfinished specs, not define the long-term documentation structure.