Routes reference¶
What Register mounts, what each route answers with, and which headers come back.
Paths below use the defaults; substitute whatever you passed to
WithSpecPath and WithDocsPath.
What Register mounts on the mux¶
Three patterns, in net/http 1.22 method-pattern form:
| Pattern | Handler |
|---|---|
GET /openapi.yaml |
writes the spec bytes you passed to Register |
GET /docs/{$} |
the generated Stoplight index HTML |
GET /docs/ |
http.FileServer over the embedded assets, with the docs prefix stripped |
{$} matches the docs path exactly and nothing below it, so the index page and the
asset subtree do not collide. Each Register call is independent: two calls with
different paths mount six routes and serve two API versions side by side. Two calls
sharing a path panic — see what happens when a path is
wrong.
Which methods each route answers¶
Patterns are registered for GET only, and net/http matches HEAD against a
GET pattern automatically.
| Request | Response |
|---|---|
GET, HEAD |
200, as described below |
POST, PUT, DELETE, OPTIONS, anything else |
405 Method Not Allowed, Allow: GET, HEAD |
The 405 comes from ServeMux, not from this module. There is no OPTIONS
handling and no CORS preflight support — the docs are designed to be served
same-origin with the API, so there is nothing to preflight.
GET /openapi.yaml — the spec¶
Returns the spec byte slice verbatim with Content-Type: application/yaml and no
other body processing: no parsing, no validation, no reformatting.
Content-Type is application/yaml unconditionally. A JSON OpenAPI document is
still served, and still renders in the UI, but with a YAML content type — JSON is a
subset of YAML, so parsers accept it, but a client keying off the content type will
be misled.
A nil or empty spec is not an error: the route registers and returns 200 with an
empty body. The docs page then loads and fails to find a document to render.
GET /docs/ — the generated page¶
Returns 200 with Content-Type: text/html; charset=utf-8 and a small HTML
document — around 530 bytes — that loads the embedded Stoplight assets and mounts
one <elements-api> element:
<elements-api
apiDescriptionUrl="/openapi.yaml"
router="hash"
layout="sidebar"
tryItCredentialsPolicy="same-origin"
></elements-api>
Only apiDescriptionUrl and the page <title> vary — they come from WithSpecPath
and WithTitle. router, layout and tryItCredentialsPolicy are fixed; there is
no option to change them.
router="hash" means deep links into the reference are fragments —
/docs/#/paths/v1-greeting/get — so navigation inside the UI never reaches your
server, and the fragment is never sent with the request.
A request for /docs without the trailing slash is redirected by ServeMux with
307 Temporary Redirect to /docs/.
GET /docs/{asset} — the embedded UI¶
http.FileServer over the two embedded files:
| Asset | Size | Content-Type |
|---|---|---|
web-components.min.js |
2,083,081 bytes | text/javascript; charset=utf-8 |
styles.min.css |
297,495 bytes | text/css; charset=utf-8 |
Anything else under the prefix is 404. /docs/index.html is redirected to ./ by
http.FileServer's own index handling, which lands on the generated page.
Responses carry no cache validators. The embedded filesystem reports a zero
modification time, so http.ServeContent emits neither Last-Modified nor ETag,
and nothing sets Cache-Control. A conditional request is answered 200 with the
full body rather than 304, so every uncached load of the docs page transfers the
whole 2.4 MB again. Put a caching proxy or a Cache-Control-setting middleware in
front if that traffic matters — this module does not do it for you.
Response headers¶
Every one of the three routes goes through the same security-header middleware
unless you passed WithoutSecurityHeaders:
| Header | Default value |
|---|---|
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY |
Content-Security-Policy |
frame-ancestors 'none' |
Referrer-Policy |
no-referrer |
Strict-Transport-Security |
not set — HSTS is opt-in |
The Stoplight console renders and issues try-it requests normally under these defaults; they restrict framing and sniffing, not scripting.
X-Frame-Options: DENY and frame-ancestors 'none' do mean the docs page cannot be
embedded in an <iframe> on another page — including your own portal. Relax it with
WithSecurityHeaderOptions if you need
that.
Replacing the policy with a full CSP is a sharper edge: WithContentSecurityPolicy
replaces the whole header, and the generated page carries an inline
style="height: 100vh; margin: 0" attribute on <body> while Stoplight injects
styles at runtime. A policy without 'unsafe-inline' in style-src will break the
page's layout.