first commit
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# `handler` — `createRedocUiHandler`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
This module exposes `createRedocUiHandler`, the factory the api-host calls
|
||||
to obtain the HTTP handler serving the ReDoc HTML shell. The returned
|
||||
handler is a zero-argument function the host invokes per request. It is
|
||||
intentionally router-agnostic — adapters in the api-host layer translate
|
||||
the returned `RedocHttpResponse` into Hono / api-router envelopes — so the
|
||||
package can be wired into any HTTP surface without dragging a router peer
|
||||
dependency through every consumer.
|
||||
|
||||
## Features
|
||||
|
||||
- Validates options at construction; invalid input raises
|
||||
`OPENAPI_UI_REDOC_INVALID_OPTIONS` before any handler runs.
|
||||
- Resolves the runtime asset URL up-front; missing bundled / inline payloads
|
||||
raise `OPENAPI_UI_REDOC_ASSETS_MISSING` at construction, not at request time.
|
||||
- Pre-renders the HTML shell once at construction — every subsequent request
|
||||
is a constant-time return of the frozen response object.
|
||||
- The response carries `Content-Type: text/html; charset=utf-8`,
|
||||
`Cache-Control: no-cache`, and `X-Content-Type-Options: nosniff`.
|
||||
- The handler is idempotent — the same call always returns the same frozen
|
||||
object, so adapters can safely cache it.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { createRedocUiHandler } from "@suaveplan/api-openapi-ui-redoc/handler";
|
||||
|
||||
const handler = createRedocUiHandler({ openapiUrl: "/openapi.json" });
|
||||
const res = handler();
|
||||
// res.body is the rendered HTML shell.
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
Wire the bundled-asset strategy into a Hono app, including the cache-busted
|
||||
asset route:
|
||||
|
||||
```ts
|
||||
import { Hono } from "hono";
|
||||
import {
|
||||
createRedocUiHandler,
|
||||
defineRedocAsset,
|
||||
} from "@suaveplan/api-openapi-ui-redoc";
|
||||
|
||||
const asset = defineRedocAsset(
|
||||
"redoc.standalone.js",
|
||||
"application/javascript; charset=utf-8",
|
||||
runtimeBody
|
||||
);
|
||||
|
||||
const handler = createRedocUiHandler({
|
||||
openapiUrl: "/openapi.json",
|
||||
uiAssets: "bundled",
|
||||
bundledAsset: asset,
|
||||
title: "Acme API",
|
||||
expandResponses: "200,201",
|
||||
theme: "dark",
|
||||
});
|
||||
|
||||
const app = new Hono();
|
||||
app.get("/docs/ui/redoc", (c) => {
|
||||
const r = handler();
|
||||
Object.entries(r.headers).forEach(([k, v]) => c.header(k, v));
|
||||
return c.body(r.body, r.status);
|
||||
});
|
||||
app.get(`/docs/ui/redoc/assets/${asset.hash}/${asset.name}`, (c) => {
|
||||
c.header("Content-Type", asset.contentType);
|
||||
c.header("Cache-Control", "public, max-age=31536000, immutable");
|
||||
return c.body(asset.body as string);
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
| Symbol | Kind | Description |
|
||||
| --------------------------- | ---- | ----------- |
|
||||
| `RedocHttpResponse` | type | `{ status, headers, body }` — router-agnostic response |
|
||||
| `RedocHttpHandler` | type | `() => RedocHttpResponse` |
|
||||
| `CreateRedocUiHandlerInput` | type | `RedocUiOptionsInput & { bundledAsset?, inlineAsset? }` |
|
||||
| `createRedocUiHandler` | fn | Build the handler; pre-renders the shell |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The handler pre-renders the HTML once at construction. This keeps the
|
||||
per-request hot path a constant-time return of a frozen object — the same
|
||||
shape the api-router would otherwise have to allocate per call. Pre-rendering
|
||||
also means every option-level fault surfaces at host start-up, not at the
|
||||
first request, which is the failure mode operators want for misconfigured
|
||||
deploys.
|
||||
Reference in New Issue
Block a user