OpenAPI
vix::openapi provides OpenAPI generation and built-in API documentation routes for Vix Core.
Use it when you want to expose an OpenAPI 3 document from a Vix router and serve an offline Swagger UI page for your HTTP application.
Public header
#include <vix/openapi/OpenApi.hpp>To register the documentation routes, include:
#include <vix/openapi/register_docs.hpp>What OpenAPI provides
The OpenAPI module provides:
- OpenAPI 3.0.3 JSON generation
- route documentation from the Vix router
- extra documentation registered by modules
- stable
operationIdgeneration - default responses when no route response metadata exists
/openapi.jsonroute registration/docsSwagger UI route registration- embedded Swagger UI CSS and JavaScript assets
- offline documentation UI with no external CDN dependency
Basic model
The OpenAPI generator reads route metadata from the router.
Router
-> routes()
-> RouteDoc
-> OpenAPI JSONIt also reads extra docs from the global OpenAPI registry.
Registry
-> extra module docs
-> OpenAPI JSONThe final document is built as:
router routes + registry docs
-> OpenAPI 3.0.3 documentGenerate OpenAPI from a router
#include <vix.hpp>
#include <vix/openapi/OpenApi.hpp>
int main()
{
vix::App app;
app.get("/status", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({{"status", "ok"}});
});
auto doc = vix::openapi::build_from_router(
*app.router(),
"My API",
"1.0.0");
vix::print(doc.dump(2));
return 0;
}Register OpenAPI and docs routes
Use register_openapi_and_docs(...) to add built-in documentation routes to a router.
#include <vix.hpp>
#include <vix/openapi/register_docs.hpp>
int main()
{
vix::App app;
app.get("/status", [](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({{"status", "ok"}});
});
vix::openapi::register_openapi_and_docs(
*app.router(),
"My API",
"1.0.0");
app.run(8080);
return 0;
}Then open:
http://localhost:8080/openapi.jsonor:
http://localhost:8080/docsRegistered routes
register_openapi_and_docs(...) registers these routes:
GET /openapi.json
GET /docs
GET /docs/
GET /docs/index.html
GET /docs/swagger-ui.css
GET /docs/swagger-ui-bundle.js/openapi.json
The /openapi.json route returns the generated OpenAPI 3 document.
GET /openapi.jsonResponse content type:
application/json; charset=utf-8The route also sets:
Cache-Control: no-store
X-Content-Type-Options: nosniff/docs
The /docs route serves the Swagger UI page.
GET /docsIt renders the generated /openapi.json document.
The Swagger UI assets are served locally from embedded assets.
/docs/swagger-ui.css
/docs/swagger-ui-bundle.jsThis means the docs UI can work without loading Swagger UI from an external CDN.
/docs/ and /docs/index.html
These routes serve the same docs page as /docs.
GET /docs/
GET /docs/index.htmlThey are registered directly to avoid redirect loops and to support static-like expectations.
OpenAPI document shape
The generated document starts with:
{
"openapi": "3.0.3",
"info": {
"title": "Vix API",
"version": "1.31.0"
},
"paths": {},
"components": {}
}The title and version can be customized.
auto doc = vix::openapi::build_from_router(
router,
"My API",
"1.0.0");Route documentation
OpenAPI metadata comes from vix::router::RouteDoc.
vix::router::RouteDoc doc;
doc.summary = "Get status";
doc.description = "Returns the current service status.";
doc.tags = {"system"};
doc.responses["200"] = {
{"description", "OK"}
};A RouteDoc can contain:
| Field | Purpose |
|---|---|
summary | Short one-line route summary. |
description | Longer route description. |
tags | OpenAPI tags. |
request_body | OpenAPI request body object. |
responses | OpenAPI responses object. |
x | Vendor-specific OpenAPI extensions. |
RouteDoc example
vix::router::RouteDoc doc;
doc.summary = "Create user";
doc.description = "Creates a new user.";
doc.tags = {"users"};
doc.request_body = {
{"required", true},
{"content", {
{"application/json", {
{"schema", {
{"type", "object"},
{"properties", {
{"name", {{"type", "string"}}}
}}
}}
}}
}}
};
doc.responses["201"] = {
{"description", "User created"}
};Register a documented route manually
Advanced code can register a route directly on the router with documentation metadata.
#include <vix.hpp>
int main()
{
vix::App app;
using Fn = std::function<void(vix::Request &, vix::Response &)>;
auto handler = std::make_shared<vix::http::RequestHandler<Fn>>(
"/status",
[](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({{"status", "ok"}});
});
vix::router::RouteDoc doc;
doc.summary = "Service status";
doc.description = "Returns whether the service is running.";
doc.tags = {"system"};
doc.responses["200"] = {{"description", "OK"}};
app.router()->add_route(
"GET",
"/status",
handler,
vix::router::RouteOptions{},
doc);
app.run(8080);
return 0;
}Most applications should register routes through App.
Direct router registration is mainly useful for tooling, generated routes, or framework internals.
OpenAPI method conversion
method_to_openapi(...) converts HTTP methods to OpenAPI operation keys.
vix::openapi::method_to_openapi("GET");Result:
getSupported methods:
GET
POST
PUT
DELETE
PATCH
HEAD
OPTIONS
TRACEUnsupported methods return an empty string.
Default responses
If a route has no response documentation, Vix adds a default response.
{
"200": {
"description": "OK"
}
}This is produced by:
vix::openapi::default_responses();Operation IDs
Vix generates a stable operationId from method and path.
vix::openapi::make_operation_id("get", "/users/{id}");Result shape:
get__users__idThe function keeps letters and numbers.
Other characters are replaced with _.
This gives client generators a stable operation name.
Build from router
Use build_from_router(...) to create the OpenAPI JSON document.
nlohmann::json doc = vix::openapi::build_from_router(
router,
"Vix API",
"1.31.0");Signature:
nlohmann::json build_from_router(
const vix::router::Router &router,
std::string title = "Vix API",
std::string version = "1.31.0");It includes:
- routes declared in the HTTP router
- extra docs registered in
vix::openapi::Registry - default responses for undocumented responses
- route summaries, descriptions, tags, request bodies, responses, and extensions
Extra route docs
Some modules may need to document routes that are not registered directly in the core router.
Use vix::openapi::Registry.
vix::router::RouteDoc doc;
doc.summary = "WebSocket endpoint";
doc.description = "Upgrades the connection to WebSocket.";
doc.tags = {"websocket"};
doc.responses["101"] = {{"description", "Switching Protocols"}};
vix::openapi::Registry::add(
"GET",
"/ws",
doc);The next call to build_from_router(...) includes this extra route documentation.
Registry
Registry is a global registry for additional OpenAPI route docs.
It provides:
vix::openapi::Registry::add(method, path, doc);
vix::openapi::Registry::snapshot();
vix::openapi::Registry::clear();Use it for:
- WebSocket docs
- module docs
- generated docs
- routes managed outside the normal router
- plugin-style integrations
ExtraRouteDoc
ExtraRouteDoc stores one extra documented route.
struct ExtraRouteDoc
{
std::string method;
std::string path;
vix::router::RouteDoc doc;
};Add extra docs
vix::router::RouteDoc doc;
doc.summary = "Health check";
doc.tags = {"system"};
doc.responses["200"] = {{"description", "OK"}};
vix::openapi::Registry::add("GET", "/health", doc);Read registry snapshot
const auto docs = vix::openapi::Registry::snapshot();
for (const auto &entry : docs)
{
vix::print(entry.method, entry.path);
}snapshot() returns a copy, so it is safe to iterate without holding the registry lock.
Clear registry
vix::openapi::Registry::clear();This removes all registered extra route docs.
It is useful for tests or when rebuilding docs in controlled environments.
Duplicate handling
When OpenAPI is built, duplicate route keys are ignored after the first occurrence.
The duplicate key is:
method + pathExample:
GET /statusIf the same method and path appear more than once between the router and registry, only the first one is kept.
Vendor extensions
RouteDoc::x can store OpenAPI vendor extensions.
vix::router::RouteDoc doc;
doc.x["x-vix-runtime"] = "core";
doc.x["x-vix-heavy"] = true;These fields are copied into the generated OpenAPI operation.
Result shape:
{
"x-vix-runtime": "core",
"x-vix-heavy": true
}Request body metadata
Use RouteDoc::request_body to describe request bodies.
doc.request_body = {
{"required", true},
{"content", {
{"application/json", {
{"schema", {
{"type", "object"},
{"properties", {
{"name", {{"type", "string"}}},
{"email", {{"type", "string"}}}
}}
}}
}}
}}
};This becomes:
{
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object"
}
}
}
}
}Response metadata
Use RouteDoc::responses to describe possible responses.
doc.responses["200"] = {
{"description", "OK"}
};
doc.responses["404"] = {
{"description", "User not found"}
};If responses is empty, Vix adds:
{
"200": {
"description": "OK"
}
}Tags
Use tags to group routes in Swagger UI.
doc.tags = {"users"};Example with multiple tags:
doc.tags = {"users", "admin"};Docs routes metadata
The docs routes also receive route documentation.
For example:
GET /openapi.jsonhas a docs tag and a summary like:
OpenAPI specThis means the docs routes can appear in the generated OpenAPI document too.
Enable docs with vix run
vix run keeps OpenAPI/docs disabled by default.
To enable docs for one run:
vix run api --docsThis sets:
VIX_DOCS=1To keep docs disabled:
vix run api --no-docsThis sets:
VIX_DOCS=0Recommended local usage
During development:
vix run api --docsThen open:
http://localhost:8080/docsFor normal runs:
vix run apiDocs stay disabled unless you explicitly enable them.
Recommended production usage
For production, expose docs only when needed.
Common approaches:
disable docs completely
protect /docs behind auth
serve docs only in internal environments
serve /openapi.json only in CI or stagingIf docs are enabled publicly, make sure your API metadata does not expose sensitive internal details.
OpenAPI and App
In normal Vix Core, docs registration can be done through the router.
vix::openapi::register_openapi_and_docs(
*app.router(),
"My API",
"1.0.0");After registration:
/openapi.json
/docs
/docs/
/docs/index.html
/docs/swagger-ui.css
/docs/swagger-ui-bundle.jsare available.
Complete example
#include <vix.hpp>
#include <vix/openapi/register_docs.hpp>
int main()
{
vix::App app;
vix::router::RouteDoc status_doc;
status_doc.summary = "Get status";
status_doc.description = "Returns the current service status.";
status_doc.tags = {"system"};
status_doc.responses["200"] = {
{"description", "OK"}
};
using Fn = std::function<void(vix::Request &, vix::Response &)>;
auto status_handler = std::make_shared<vix::http::RequestHandler<Fn>>(
"/api/status",
[](vix::Request &req, vix::Response &res)
{
(void)req;
res.json({
{"status", "ok"}
});
});
app.router()->add_route(
"GET",
"/api/status",
status_handler,
vix::router::RouteOptions{},
status_doc);
vix::openapi::register_openapi_and_docs(
*app.router(),
"Example API",
"1.0.0");
app.run(8080);
return 0;
}Open:
http://localhost:8080/openapi.jsonor:
http://localhost:8080/docsAPI summary
| API | Purpose |
|---|---|
method_to_openapi(method) | Convert an HTTP method to an OpenAPI operation key. |
default_responses() | Return the default 200 OK response object. |
make_operation_id(method, path) | Build a stable operation ID from method and path. |
build_from_router(router, title, version) | Build an OpenAPI 3 document from the router and registry. |
register_openapi_and_docs(router, title, version) | Register /openapi.json and /docs routes. |
Registry::add(method, path, doc) | Register extra route documentation. |
Registry::snapshot() | Return a copy of registered extra docs. |
Registry::clear() | Clear extra docs. |
RouteDoc summary
| Field | Purpose |
|---|---|
summary | One-line operation summary. |
description | Detailed operation description. |
tags | Grouping tags for the operation. |
request_body | OpenAPI request body metadata. |
responses | OpenAPI responses metadata. |
x | Vendor-specific extensions. |
Header map
| Area | Header |
|---|---|
| OpenAPI generator | <vix/openapi/OpenApi.hpp> |
| Registry | <vix/openapi/Registry.hpp> |
| Docs route registration | <vix/openapi/register_docs.hpp> |
| Route documentation | <vix/router/RouteDoc.hpp> |
| Router | <vix/router/Router.hpp> |
| Docs UI | <vix/openapi/DocsUI.hpp> |
| Swagger assets | <vix/openapi/assets/SwaggerAssets.hpp> |
Best practices
Enable docs explicitly during development.
vix run api --docsUse clear route summaries.
doc.summary = "Create user";Group routes with tags.
doc.tags = {"users"};Always document expected responses.
doc.responses["200"] = {{"description", "OK"}};
doc.responses["404"] = {{"description", "Not found"}};Use Registry for routes that are not directly stored in the core router.
vix::openapi::Registry::add("GET", "/ws", doc);Avoid exposing sensitive internal information in public docs.
Keep production docs intentional.Next steps
Read the related pages: