generateOpenApi
Generate an OpenAPI 3.1.0 document from a Kizuna api.
Generate an OpenAPI 3.1.0 document from your api. Returns a renderer you call with 'json' or 'yaml'.
pnpm add @kizunajs/openapi@betabun add @kizunajs/openapi@betanpm install @kizunajs/openapi@betaimport { generateOpenApi } from '@kizunajs/openapi';Parameters
generateOpenApi(api: ApiDefinition, overrides?: Partial<GenerateOpenApiOptions>): OpenApiRenderer| Parameter | Type | Description |
|---|---|---|
api | ApiDefinition | The api from defineConfig |
overrides | Partial<GenerateOpenApiOptions> | Merged over the plugin's options, for what only a build knows |
It lives on @kizunajs/openapi, beside openApiPlugin and the document types.
Options
Options are declared on openApiPlugin, and generateOpenApi reads them off the api, so a build step cannot write a document that differs from the one your server serves. Pass overrides for what only a build step knows, such as the public servers list.
| Option | Type | Default | Description |
|---|---|---|---|
info | { title, version, description? } | required | OpenAPI info object |
openApiVersion | '3.1.0' | '3.1.0' | OpenAPI specification version for the generated document |
servers | { url, description? }[] | none | Server URLs |
setOperationId | boolean | 'concatenated-path' | false | Set operationId from the route key. Use 'concatenated-path' to include parent keys. |
externalDocs | { url, description? } | none | Top-level external documentation link |
operationMapper | (operation, route, id) => operation | none | Callback to transform each operation before it is added to the spec |
derivedHead | boolean | false | Document the derived head operation on every GET path without a declared one |
There are no security or tag options. Security is emitted from each route's auth and the document's tag list from k.tags, so neither can disagree with what the server enforces.
Returns
An OpenApiRenderer function:
renderer('json'); // OpenApiDocument object
renderer('yaml'); // YAML stringExample
import { defineConfig } from 'kizunajs';
import { openApiPlugin } from '@kizunajs/openapi';
import { routes } from './src/routes';
export default defineConfig({
adapter: expressAdapter(),
routes,
plugins: [
openApiPlugin({
info: {
title: 'My API',
version: '1.0.0',
},
servers: [
{
url: 'https://api.example.com',
description: 'Production',
},
],
setOperationId: true,
}),
],
});import { generateOpenApi } from '@kizunajs/openapi';
import kizuna from '../kizuna.config';
const spec = generateOpenApi(kizuna.api);
app.get('/openapi.json', (_req, res) => {
res.json(spec('json'));
});Security emission
Security is generated from what you declared, not configured on the generator. Every identity named under auth.identities on defineConfig is emitted under components.securitySchemes, and every route with an auth references those names in its security, with the permissions an OAuth route requires as its scopes. Public routes (false) get none.
With the user (bearer) and member (API key) identities, and a workspace route declaring auth: 'member', the document contains:
components:
securitySchemes:
user:
type: http
scheme: bearer
member:
type: apiKey
name: x-workspace-token
in: header
paths:
/workspace:
get:
security:
- member: []A custom identity is the exception: OpenAPI can't describe its credential, so it emits no securityScheme and no security. Its routes instead carry an x-kizuna-guarded extension, keeping a protected-out-of-band route distinct from a public one.
A route with roles carries them under x-kizuna-roles, ['owner'], and one with requires carries the permissions under x-kizuna-requires, { workspace: ['delete'] }, so a reader of the document sees who the caller has to be.
The spec and the runtime guards both derive from the same auth, so documented security is enforced security.
See the OpenAPI guide for Scalar integration, writing specs to disk, and breaking change detection.