Hosting Docs UI (CloudFront / Pages)
Hosting Docs UI (CloudFront / Pages)
Section titled “Hosting Docs UI (CloudFront / Pages)”Serve the Callspec Docs UI behind CloudFront, S3, or Cloudflare/Netlify Pages so it feels like a native product surface — without Fern.
Live data (callspec.json, OpenAPI, RPC, MCP) always comes from your API process. Only the UI shell and assets can move to a CDN.
Choose a pattern
Section titled “Choose a pattern”| Pattern | When to use | Callspec work |
|---|---|---|
| A — Reverse proxy | Same origin as the API; simplest | None (document + infra) |
| B — Static export | UI on S3/Pages; API elsewhere | export-docs-ui + absolute URLs + CORS |
| C — Shared SPA distribution | Apex path like /docs next to marketing | Infra behaviors (+ A or B) |
Pattern A — Reverse proxy → API
Section titled “Pattern A — Reverse proxy → API”Browser → CloudFront / Pages → api.example.com/v1/docs/All /docs/*, callspec.json, RPC, and MCP hit the API (via CloudFront behavior, Caddy, or ALB). Relative specUrl / rpcBase from mountSpec keep working.
- Pros: No export step; try-it and MCP stay colocated
- Cons: HTML is not a pure edge object (cache GET
/docs/with a short TTL if you want) - Logfox fit: CloudFront behavior or path rewrite on the API host
No Callspec code changes. Use Express cache headers from mountCallspecUi (HTML no-cache, hashed JS/CSS immutable).
Pattern B — Static UI on CDN + API for JSON/RPC
Section titled “Pattern B — Static UI on CDN + API for JSON/RPC”/docs/* → S3 + CloudFront (exported shell + assets)/v1/* → API (callspec.json, openapi.json, RPC, MCP)- Build Callspec (
npm run buildor install the published package). - Export a deployable folder:
callspec export-docs-ui --out ./docs-ui-dist \ --spec-url https://api.example.com/v1/callspec.json \ --rpc-base https://api.example.com/v1 \ --mcp-url https://api.example.com/v1/mcp \ --title "Acme API"- Upload
docs-ui-dist/(aws s3 sync, Pages, Netlify). - Enable CORS on the API for the docs origin (try-it browser fetches).
- Set CDN
Cache-Controlfor hashed/assets/*to long-lived / immutable; keepindex.htmlshort TTL orno-cache.
Absolute specUrl, rpcBase, and mcp.url are plain strings — the browser fetch / URL APIs accept them as-is.
When --rpc-base is an http(s) URL and you omit --mcp-path / --mcp-url, export defaults mcpPath to {rpcBase}/mcp so MCP does not resolve against the CDN docs origin.
Pattern C — Same distribution as a marketing SPA
Section titled “Pattern C — Same distribution as a marketing SPA”Extend your static frontend CloudFront (or Pages) map:
| Path | Origin |
|---|---|
/docs/* | S3 (exported UI) or API reverse proxy (Pattern A) |
/* | Marketing / app SPA |
Subpath on the apex (example.com/docs) is DNS + behaviors — not a separate docs. host.
CloudFront sketch (Pattern B)
Section titled “CloudFront sketch (Pattern B)”- Behavior
/docs/assets/*→ S3; cache policy honors originCache-Control(hashed JS/CSS areimmutable) - Behavior
/docs*→ S3;index.htmlshort TTL /no-cache - API remains a separate origin for
/v1/*(or your mount)
Pages / Netlify rewrite (Pattern A)
Section titled “Pages / Netlify rewrite (Pattern A)”Point /docs/* (and API paths you need) at the API origin — same idea as a Fern reverse proxy. Prefer Pattern A when you do not need a separate static bucket.
CORS checklist (Pattern B)
Section titled “CORS checklist (Pattern B)”- Allow the docs origin on API CORS
- Allow methods used by try-it (
POST,OPTIONS) - Allow
Authorizationif routes use bearer auth - MCP over HTTP may need the same origin allowlist depending on the client