OpenAPI
Auto-generated API reference pages from an OpenAPI spec.
~ 2 min read
OpenAPI
Point Tangly at an OpenAPI spec; every endpoint becomes a page.
Top-level setup
In docs.json:
{
"api": {
"openapi": "https://api.example.com/openapi.json",
"viewer": "tangly",
"auth": { "method": "bearer", "name": "Authorization" }
}
}Tangly fetches the spec at build time. openapi accepts a URL, a local path (relative to project root), or an array of either.
Viewer choice
viewer selects the rendering engine:
| Value | Render |
|---|---|
tangly (default) | Built-in compact endpoint render. Server-fetched at build time. |
scalar | Scalar viewer, lazy-loaded from CDN. |
redoc | ReDoc viewer, lazy-loaded from CDN. |
stoplight | Stoplight Elements, lazy-loaded from CDN. |
The default tangly renderer is fastest and works without client JS. The third-party viewers add interactivity but pull bundles from CDN at runtime.
Per-endpoint pages
A page with openapi: in frontmatter auto-generates the endpoint:
---
title: Get network data
openapi: get /v4/data/network/{network_code}
---The page renders:
- HTTP method badge + path
- Summary + description from the operation
- Parameters table (path / query / header / body)
- Request and response schemas
- Try-it-out form (when
playground.modeisinteractive)
Companion narrative
Add MDX content alongside the auto-rendered endpoint by setting api: instead of openapi::
---
title: Get network data
api: GET /v4/data/network/{network_code}
---
# Background
This endpoint returns time-series data sliced by network. Cache for at least 60s — backend regenerates the underlying view every minute.
## Common pitfalls
- Pass `interval=5m` for production dashboards.
- Time ranges over 30 days are rate-limited.Tangly merges your narrative with the auto-generated endpoint render. Both stay in sync as the spec evolves.
Auto-generated tab
Set openapi on a tab node to materialize one page per endpoint:
{
"tab": "API Reference",
"openapi": "./openapi.json"
}Tangly walks the spec, generates a synthetic PageEntry for each operation, and appends them to the tab’s sidebar grouped by tag.
Authentication
Configure auth at the top level so try-it-out forms include credentials:
{
"api": {
"auth": { "method": "bearer", "name": "Authorization" }
}
}method | Behavior |
|---|---|
bearer | Adds Authorization: Bearer <token> to requests. Token comes from a per-page input. |
basic | Adds Authorization: Basic <base64>. |
key | Adds <name>: <value> header (or query param if the spec says so). |
none | No auth. |
Multi-environment base URLs
{
"api": {
"baseUrl": ["https://api.example.com", "https://staging-api.example.com"]
}
}The try-it-out form gets a server selector.
Local specs
Local OpenAPI files are resolved relative to project root:
{ "api": { "openapi": "./openapi.json" } }The Vite static-asset middleware doesn’t auto-serve OpenAPI files — they’re loaded server-side at build time, not via HTTP.
Validation
tangly check validates your spec via @apidevtools/swagger-parser:
bun x tangly check --strictBad refs, missing schemas, malformed operations all surface as errors before you build.