Skip to Content
Customizing the Client

TypeScript Client Customization

You can customize the generated TypeScript client by replacing imports of lower-level libraries. Do this via the outputConfig.imports object in the config file, which can specify a fetcher and validateOnClient.

By default, when vovk-ajv (described below) is used for client-side validation, an index.mjs file generating the UserRPC module might look like:

./node_modules/.vovk-client/index.mjs
import { createRPC } from 'vovk'; import { schema } from './schema.cjs'; export const UserRPC = createRPC(schema, '', 'UserRPC', import('vovk'), { validateOnClient: import('vovk-ajv'), apiRoot: 'http://localhost:3000/api', });

When outputConfig.imports is modified:

vovk.config.mjs
/** @type {import('vovk').VovkConfig} */ const config = { outputConfig: { imports: { fetcher: './src/lib/fetcher', validateOnClient: './src/lib/validateOnClient', }, }, }; export default config;

The generated index.mjs uses these imports and resolves relative paths:

./node_modules/.vovk-client/index.mjs
import { createRPC } from '../../src/lib/createRPC'; export const UserRPC = createRPC(schema, '', 'UserRPC', import('../../src/lib/fetcher'), { validateOnClient: import('../../src/lib/validateOnClient'), apiRoot: 'http://localhost:3000/api', });

fetcher and validateOnClient can also be set per segment. This enables different options or auth mechanisms per segment (including OpenAPI mixins) and different validation libraries where needed.

/** @type {import('vovk').VovkConfig} */ const config = { outputConfig: { imports: { // applied to all segments fetcher: './src/lib/fetcher', validateOnClient: './src/lib/validateOnClient', }, segments: { admin: { imports: { // applied only to "admin" segment fetcher: './src/lib/adminFetcher', validateOnClient: './src/lib/adminValidateOnClient', }, }, }, }, }; export default config;

fetcher

The fetcher prepares handlers, performs client-side validation, issues HTTP requests, differentiates content types (JSON, JSON Lines, or other Response types), and returns data in the appropriate format.

  • For application/json, it returns the parsed JSON.
  • For application/jsonl or application/jsonlines, it returns a disposable async iterable.
  • For other content types, it returns the Response object as-is, letting you access text or binary data.

It can also process custom per-call options passed to RPC methods.

import { UserRPC } from 'vovk-client'; const user = await UserRPC.updateUser({ // ... successMessage: 'Successfully updated the user', someOtherCustomFlag: true, });

createFetcher

The file at imports.fetcher must export a fetcher variable. To simplify creating a custom fetcher, use createFetcher from vovk.

./src/lib/fetcher.ts
import { createFetcher } from 'vovk'; export const fetcher = createFetcher<{ successMessage?: string; // "Successfully created a new user" useAuth?: boolean; // if true, Authorization header will be set someOtherCustomFlag?: boolean; // any custom flag that you want to pass to the RPC method }>({ prepareRequestInit: async (init, { useAuth, someOtherCustomFlag }) => { // ... return { ...init, headers: { ...init.headers, ...(useAuth ? { Authorization: 'Bearer token' } : {}), }, }; }, transformResponse: async (data, { someOtherCustomFlag }) => { // ... return { ...data, }; }, onSuccess: async (data, { successMessage }) => { if (successMessage) { alert(successMessage); } }, onError: async (error) => { alert(error.message); }, });

With this setup, all RPC module methods accept the desired options:

import { UserRPC } from 'vovk-client'; await UserRPC.updateUser({ params: { param: 'value' }, query: { id: 'value' }, body: { email: 'value' }, successMessage: 'Successfully updated the user', useAuth: true, someOtherCustomFlag: true, });

createFetcher accepts an object with:

prepareRequestInit(init: RequestInit, options: T)

Prepares RequestInit before making the request. Use it to set auth headers or Next.js-specific next options. Receives the prepared init and custom call options, and must return a RequestInit object (usually based on init). Useful for logging or other pre-request logic.

transformResponse(data: unknown, options: T, info: { response: Response, init: RequestInit, schema: VovkHandlerSchema })

Transforms the response before returning it to the caller. The data type depends on the content type: JSON, a disposable  async iterator , or a Response. Return the transformed value. The info argument provides the original Response, the RequestInit used, and the VovkHandlerSchema (e.g., schema.operationObject).

onError(error: HttpException, options: T)

Called when a request fails. Use it for error messages, logging, or custom handling.

onSuccess(data: unknown, options: T)

Called on success. Use it for success messages, logging, or post-processing.

validateOnClient

validateOnClient defines how client-side validation is performed for RPC/API method input (params, query, body). Create it via createValidateOnClient from vovk. It accepts a validate function that receives the input data, the JSON schema, and metadata, and returns validated data or throws on failure. Validation runs only when both input and schema are provided.

./src/lib/validateOnClient.ts
import { validateData } from 'some-json-validation-library'; import { createValidateOnClient, HttpException, HttpStatus } from 'vovk'; export const validateOnClient = createValidateOnClient({ validate: async (input, schema, meta) => { const isValid = validateData(input, schema); if (!isValid) { throw new HttpException(HttpStatus.NULL, 'Validation failed', { // ... optional cause }); } return input; }, });

vovk-ajv

vovk-ajv  is the primary library for client-side validation, built on top of Ajv . It’s installed and configured automatically when you run npx vovk-cli init. vovk-ajv supports additional configuration under config.libs.ajv in vovk.config, including Ajv options, localization, and the target JSON Schema draft.

npm install vovk-ajv
vovk.config.mjs
/** @type {import('vovk').VovkConfig} */ const config = { outputConfig: { imports: { validateOnClient: 'vovk-ajv', }, }, libs: { /** @type {import('vovk-ajv').VovkAjvConfig} */ ajv: { options: { // Ajv options strict: false, }, localize: 'en', // language supported by "ajv-i18n" target: 'draft-07', // auto-detected from $schema but can be configured }, }, }; export default config;
Last updated on