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
Utilizing the Generated OpenAPI Specification
The generated RPC client exports an openapi object that contains the full back-end specification for the composed client. When using the segmented client, each segment also exports its own specification.
import { UserRPC, openapi } from 'vovk-client'; // composed clientimport { UserRPC, openapi } from '@/client/admin/index.ts'; // segmented clientYou can alternatively import the openapi object from vovk-client/openapi or @/client/admin/openapi to access the specification independently of the RPC modules.
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 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. We recommend Scalar because 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",
servers: [
{
url: "http://localhost:3000",
description: "Localhost",
},
{
url: "https://example.com",
description: "Production",
},
],
}}
/>
);
}
export default App;For a live demonstration, see the “Hello World” application . Additional details are available on the “Hello World” page.