Files
skills/docs/api-stack/api/api-openapi-ui-scalar/src/handler/handler.md
2026-05-29 08:20:56 +01:00

3.3 KiB

createScalarUiHandler — Scalar HTTP handler factory

(no submodules)

Purpose

The handler module owns the public createScalarUiHandler factory the host calls when host.openapi.ui = "scalar". It validates the caller-supplied options through the Zod schema, eagerly resolves the Scalar runtime asset URL (CDN or bundled), constructs the OTel instrument bundle, and returns a frozen ScalarUiHandlerBundle whose handler field is the actual HTTP handler callable. The bundle also exposes an assetHandler for the bundled-mode <uiEndpoint>/assets/ sub-route the host mounts alongside the main shell.

Features

  • Eager validation — invalid options or missing bundled assets fail at handler construction rather than at first request.
  • Strict CSP — Content-Security-Policy header value is derived once at construction time so request handling never has to recompute it. The policy widens to whitelist the CDN origin only when assetMode = "cdn".
  • Per-request CSP nonce passthrough — the handler accepts an optional nonce on each request which the renderer threads onto the inline <script> blocks.
  • Idempotent — repeated handler invocations on the same request input return byte-identical body / headers.
  • OTel — every successful HTML response increments the openapi.ui.requests_total counter with { ui: "scalar" }.

Usage: Basic

import { createScalarUiHandler } from "@suaveplan/api-openapi-ui-scalar/handler";

const { handler } = createScalarUiHandler({
    openapiUrl: "/openapi.json",
});

const response = handler({ method: "GET", path: "/docs/ui/scalar" });
console.log(response.status); // 200
console.log(response.headers["Content-Security-Policy"]);

Usage: Advanced

import { createScalarUiHandler } from "@suaveplan/api-openapi-ui-scalar/handler";

const bundle = createScalarUiHandler({
    openapiUrl: "/openapi.json",
    theme: "deepSpace",
    layout: "classic",
    assetMode: "bundled",
});

// Per-request nonce — wire into your edge / Hono / Worker middleware.
const html = bundle.handler({
    method: "GET",
    path: "/docs/ui/scalar",
    nonce: crypto.randomUUID(),
});

// Bundled-mode hosts ALSO mount the asset handler at
// `<uiEndpoint>/assets/:filename`.
const js = bundle.assetHandler({
    method: "GET",
    path: `${bundle.options.uiEndpoint}/assets/scalar.js`,
});
console.log(js.headers["Content-Type"]); // "application/javascript; charset=utf-8"

API Reference

  • CreateScalarUiHandlerInput — ScalarUiOptionsInput plus meterProvider? and bundledAssetProbe? DI hooks.
  • createScalarUiHandler(input) — ScalarUiHandlerBundle.
  • ScalarUiHandlerBundle — { name, version, options, instruments, runtimeUrl, handler, assetHandler } (frozen).
  • ScalarUiHandler — (request) => ScalarHttpResponse.

Implementation Notes

The factory pre-computes the CSP header value, the resolved runtime URL, and the OTel instrument bundle so request handling is a constant- time render + counter-increment. Mount-time validation catches every operator-config failure mode before the host accepts traffic. Errors raised here carry the stable OPENAPI_UI_SCALAR.* codes so host boot-up can discriminate without unpacking the underlying Zod issues.