Skip to content

Interactive Docs UI

Stratal serves an interactive API reference directly from your worker using Swagger UI by default. The UI reads the generated OpenAPI spec and renders a browsable, searchable interface where consumers can explore endpoints, view schemas, and try out requests.

The renderer is pluggable — you can swap Swagger UI for any renderer that returns a Hono middleware handler.

Once the OpenAPIModule is registered, the interactive docs are available at the configured UI path. With default settings, start your dev server and visit:

http://localhost:8787/api/docs

The JSON spec that powers the UI is available at:

http://localhost:8787/api/openapi.json

You can import this URL into external tools like Postman, Insomnia, or any OpenAPI-compatible client.

Change where the UI is served by passing the ui option to forRoot():

OpenAPIModule.forRoot({
info: { title: 'My API', version: '2.0.0' },
ui: { path: '/docs' },
jsonPath: '/openapi.json',
})

With this configuration:

  • Interactive docs are at /docs
  • JSON spec is at /openapi.json

The ui.renderer option accepts a function that receives an OpenAPIUIContext and returns a Hono middleware handler. This lets you replace Swagger UI with any documentation renderer.

The OpenAPIUIRenderer type is defined as:

import type { MiddlewareHandler } from 'hono'
interface OpenAPIUIContext {
specUrl: string
title: string
}
type OpenAPIUIRenderer = (context: OpenAPIUIContext) => MiddlewareHandler

Here is an example using a custom renderer:

import type { OpenAPIUIRenderer } from 'stratal/openapi'
const myRenderer: OpenAPIUIRenderer = ({ specUrl, title }) => {
return (c) => {
const html = `
<!DOCTYPE html>
<html>
<head><title>${title}</title></head>
<body>
<h1>${title}</h1>
<p>Spec available at <a href="${specUrl}">${specUrl}</a></p>
</body>
</html>
`
return c.html(html)
}
}
OpenAPIModule.forRoot({
info: { title: 'My API', version: '1.0.0' },
ui: { renderer: myRenderer },
})

Set ui to false to disable the interactive docs entirely:

OpenAPIModule.forRoot({
info: { title: 'My API', version: '1.0.0' },
ui: false,
})

The OpenAPIConfigService is request-scoped, which means you can change the docs title or apply route filters on a per-request basis. This is useful when you want to customize the documentation per environment or API version.

Here is a middleware that overrides the spec title based on a request header:

import { inject } from 'stratal/di'
import { Middleware, MiddlewareHandler } from 'stratal/middleware'
import { RouterContext } from 'stratal/router'
import { OPENAPI_TOKENS } from 'stratal/openapi'
import type { IOpenAPIConfigService } from 'stratal/openapi'
@Middleware()
export class EnvironmentDocsMiddleware implements MiddlewareHandler {
constructor(
@inject(OPENAPI_TOKENS.ConfigService)
private openApiConfig: IOpenAPIConfigService,
) {}
async handle(ctx: RouterContext, next: () => Promise<void>) {
const environment = ctx.header('X-Environment') ?? 'production'
this.openApiConfig.override({
info: {
title: `My API (${environment})`,
description: `API documentation for the ${environment} environment`,
},
})
await next()
}
}

Each request gets its own instance of OpenAPIConfigService, so overrides in one request do not affect others. The override is merged with the base configuration: any fields you set replace the base values, and any fields you omit keep their defaults.

You now have a complete picture of Stratal’s OpenAPI system. From here you can explore:

  • Controllers and Routing for more on how controllers work beyond the OpenAPI conventions.
  • Guards for protecting routes with authentication and authorization.
  • Middleware for request processing pipelines.