Skip to Content
Imports Customization

TypeScript RPC 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, validateOnClient, or createRPC.

By default (when vovk-ajv 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', createRPC: './src/lib/createRPC', }, } }; 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 modules 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 method input (params, query, body). Create it via createValidateOnClient from vovk. It accepts a validate function that receives the input data, the validation 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 '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; }, });

See client-side validation for details.

createRPC (Advanced)

createRPC lets you replace the default RPC client completely. It is configured globally (not per segment, unlike fetcher or validateOnClient). This is an advanced option with limited use cases; feel free to ask on GitHub Discussions .

Last updated on