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.
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:
params→parameterswithin: "path"query→parameterswithin: "query"body→requestBodywith theapplication/jsoncontent type (isFormchanges it tomultipart/form-data)output→responseswith status200andapplication/jsoncontent typeiteration→responseswith status200andapplication/jsonlcontent 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.
// @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.
// @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 clientimport { openapi } from '@/client/admin/openapi.ts'; // segmented clientThis 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 staticnpx vovk new controller static/openApi --emptyimport { 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.