OpenAPI¶
sphinxcontrib-openapi generates HTTP API documentation directly from OpenAPI (Swagger) specification files. It builds on sphinxcontrib-httpdomain, which provides HTTP method directives for writing endpoint docs by hand. Lumina styles all HTTP endpoints with color-coded method indicators and adds interactive features when you configure a base URL.
Setup¶
uv add sphinxcontrib-openapi
extensions = ["sphinxcontrib.openapi"]
This also installs the HTTP domain, so you can write individual endpoints manually with http:get::, http:post::, and other method directives.
Usage¶
Point the openapi directive at your spec file:
```{eval-rst}
.. openapi:: path/to/openapi.yml
```
See HTTP API Documentation for rendered examples of both auto-generated and manually written HTTP API documentation.
Interactive Features¶
Set api_base_url in your theme options to activate two interactive features on every HTTP endpoint:
html_theme_options = {
"api_base_url": "https://api.example.com/v1",
}
Copy as curl¶
A Copy as curl button appears in the signature bar of each endpoint. Clicking it copies a ready-to-run curl command to your clipboard, with:
The correct HTTP method and full URL (base URL + path)
All documented request headers (e.g.,
Authorization: Bearer <token>)A JSON body template pre-populated from documented request fields
Query parameters shown as
?param=<value>placeholders
For endpoints with multiple flags the command uses multi-line formatting for readability:
curl -X POST "https://api.example.com/v1/users" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"email":"","name":"","role":""}'
Try it out¶
A collapsible Try it out panel sits below each endpoint description. It lets readers send real HTTP requests directly from the docs page without leaving the browser.
The panel pre-populates from the documented endpoint:
Path parameters — required fields with live URL preview as you type
Query parameters — optional fields shown with their types
Authorization — bearer token input (hidden by default; persisted in
sessionStorageacross page loads)Additional headers — any other documented request headers
Request body — JSON textarea pre-filled with a schema template for POST/PUT/PATCH endpoints
After sending, the panel shows the HTTP status code, response time in milliseconds, and a syntax-highlighted JSON response body (or plain text for non-JSON responses).
Warning
CORS required. The “Try it out” panel sends requests directly from the reader’s browser. Your API must allow CORS from the docs origin, or requests fail with a network error. Many public APIs (Stripe, GitHub, Petstore) already support this.
Overriding the base URL per block¶
api_base_url sets a global default for all endpoints on all pages. To use a different server URL for a specific group of endpoints — for example, a staging environment or a separate microservice — wrap those endpoints in a <div> with a data-api-base-url attribute.
The closest ancestor’s data-api-base-url takes precedence over the global setting:
<div data-api-base-url="https://staging.api.example.com/v1">
```{eval-rst}
.. openapi:: staging-api.yml
```
</div>
This works with both .. openapi:: directives and individual .. http:get:: / .. http:post:: directives.
Note
HTML blocks in MyST require html_block in myst_enable_extensions, or use a {raw} html directive pair instead:
```{raw} html
<div data-api-base-url="https://staging.api.example.com/v1">
```
```{eval-rst}
.. openapi:: staging-api.yml
```
```{raw} html
</div>
```
The server badge (shown above the first endpoint) always reflects the global api_base_url. Per-block overrides affect only the curl commands and “Try it out” URLs.
Disabling Try it out¶
To keep the “Copy as curl” button but hide the interactive panel:
html_theme_options = {
"api_base_url": "https://api.example.com/v1",
"try_it_out": "false",
}
Bearer token persistence¶
When a reader enters a bearer token in the “Try it out” panel, it is saved to sessionStorage under the key lumina-api-token. The token is restored automatically when the panel is opened on any endpoint in the same browser tab. It is never sent to any server other than your API.
The token is cleared when the browser tab is closed (sessionStorage scope).