OpenAPI Specification and @operation Decorator
Vovk.ts automatically generates an OpenAPI specification from procedures, 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 OperationObject type from openapi3-ts/oas31 , enhanced with Vovk-specific x-tool poperty related to deriveTools function.
import { procedure, put, prefix, operation } from 'vovk';
import { z } from 'zod';
@prefix('users')
export default class UserController {
@operation({
summary: 'Update User',
description: 'Update user information',
})
@put('{id}')
static updateUser = procedure({
// ...
});
}The validation models, accepted by the procedure 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.
// @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 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 clientYou 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.
import { get, operation } from 'vovk';
import { openapi } from 'vovk-client/openapi';
export default class OpenApiController {
@get('openapi.json')
static getSpec = () => openapi;
}On the client side, you can use any OpenAPI documentation generator. Scalar is a recommended choice as Vovk.ts generates code snippets for the generated RPC modules.
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 . Check “Hello World” page for details.
The @operation decorator also provides tool property that defines tool-specific attributes for deriveTools function. It’s set under x-tool key in the OpenAPI operation object.
import { procedure, put, operation } from 'vovk';
export default class UserController {
@operation.tool({
name: 'updateUser',
description: 'Update user information in the system',
})
@operation({
summary: 'Update User',
description: 'Update user information',
})
@put('{id}')
static updateUser = procedure({
// ...
});
}For more details, see the deriveTools documentation.