Skip to Content
OpenAPI Specification

OpenAPI Specification with @operation Decorator

Vovk.ts automatically generates an OpenAPI specification from controller methods, using validation models to populate operation objects with parameters, requestBody, and responses. The @operation decorator lets you enrich operation objects with metadata such as summary, description, tags, and more. It accepts a VovkOperationObject, which extends the standard OpenAPI OperationObject type from openapi3-ts/oas31  and supports x-tool-* properties related to AI capabilities, as described in the Function Calling documentation.

src/modules/user/UserController.ts
import { put, prefix, operation } from "vovk"; import { z } from "zod"; import { withZod } from "vovk-zod"; @prefix("users") export default class UserController { @operation({ summary: "Update User", description: "Update user information", }) @put("{id}") static updateUser = withZod({ isForm: true, params: z.object({ id: z.uuid(), }), body: z.object({ /* ... */ }), query: z.object({ /* ... */ }), output: z.object({ /* ... */ }), // ... }) }

The validation models are converted to OpenAPI operation objects according to the following mapping:

  • paramsparameters with in: "path"
  • queryparameters with in: "query"
  • bodyrequestBody with the application/json content type (isForm changes it to multipart/form-data)
  • outputresponses with status 200 and application/json content type
  • iterationresponses with status 200 and application/jsonl content type

Configuring the OpenAPI Specification

The OpenAPI specification can be configured in the vovk.config file under the outputConfig.openAPIObject option. This object is merged with the generated specification, allowing you to set global properties such as info, servers, and more.

vovk.config.js
// @ts-check /** @type {import('vovk').VovkConfig} */ const config = { outputConfig: { openAPIObject: { info: { title: 'My app API', description: 'API for My App hosted at https://myapp.example.com/.', license: { name: "MIT", url: "https://opensource.org/licenses/MIT", }, version: "1.0.0", }, servers: [ { url: "https://myapp.example.com", description: "Production", }, { url: "http://localhost:3000", description: "Localhost", }, ], }, }, }; module.exports = config;

The openAPIObject can also be configured individually for each segment using outputConfig.segments.[segmentName].openAPIObject. This is useful for segmented client where each segment has its own API specification.

vovk.config.js
// @ts-check /** @type {import('vovk').VovkConfig} */ const config = { outputConfig: { segments: { admin: { openAPIObject: { info: { title: 'Admin API', description: 'API for Admin segment.', version: "1.0.0", }, }, }, }, }, };

Utilizing the Generated OpenAPI Specification

The generated RPC client exports an openapi object from openapi module that contains the full back-end specification for the composed client. When using the segmented client, each segment also exports its own specification.

import { openapi } from 'vovk-client/openapi'; // composed client
import { openapi } from '@/client/admin/openapi.ts'; // segmented client

This object is a fully compliant OpenAPI 3.x specification and works with any tool that supports OpenAPI 3 or later.

You can use the specification directly as a variable or expose it via a static segment with a simple controller that serves it as a JSON endpoint.

npx vovk new segment --static static
npx vovk new controller static/openApi --empty
src/modules/static/openapi/OpenApiController.ts
import { get, operation } from "vovk"; import { openapi } from "vovk-client/openapi"; export default class OpenApiController { @operation({ // operation object definition is optional summary: "OpenAPI Specification", description: 'Retrieve the OpenAPI specification for the API', }) @get("openapi.json") static getSpec = () => openapi; }

On the client side, you can use any OpenAPI documentation generator, but Scalar  is the best choice as Vovk.ts generates code snippets that integrate directly into your codebase.

import { ApiReferenceReact } from "@scalar/api-reference-react"; import "@scalar/api-reference-react/style.css"; async function App() { return ( <ApiReferenceReact configuration={{ url: "/api/static/openapi.json" }} /> ); } export default App;

For a live demonstration, see the “Hello World” application spec . Additional details are available on the “Hello World” page.

Last updated on