Skip to Content

Vovk.ts 3.0

The new version intoduces massive improvements that fix probably every problem previous versions had. Overall, I decided to turn this project into a serious open-source product, and not just another unknown repository on my Githib account. Starting version 3 Vovk.ts is focusing on achieving the highest quality and maximizing development experience. The project is split into multiple smaller projects, introducing the new CLI where every single detail has been well tested, new validation libraries, code generator, instllation wizard, multi-segment architecture and more. vovk package remains to have zero dependencies making almost no difference to your production bundle.

Breaking changes

  • Rename prefix RPC option to apiRoot.
  • Rename StreamResponse to JSONLinesResponse.
  • Update schema format and use .vovk-schema/ folder to generate schema for each segment separately.
  • Generate client to node_modules/.vovk-client/
  • Rename all occurrences of β€œmetadata” to β€œschema”. --- NAHUI
  • Rename some config options. See documentation
  • Remove default client validation when validateOnClient is not set in settings.
  • Move VovkEnv and VovkConfig types to vovk-cli package.
  • Completely removed Web Worker features.

New features

  • req.vovk object with body(), query(), meta() and form() methods.
  • Rethrow error cause.
  • Add devHttps setting to enable https in local development.
  • Support .config folder for the config.
  • Add prettifyClient config option
  • Finally figure out how to fix problems with query and single-item arrays.
  • Implement multi-segment mode.
  • Add endpoint info to the client error messages.
  • transform option for client methods to transform response data.
  • Client method accepts fetcher and validateOnClient options.

Noteworthy fixes

  • Simplify types and allow to use circular references in service-controller pair. Big thanks to Anders Hejlsberg  , the lead architect of TypeScript, for the solution for #58616 .
  • Get rid of VOVK_PORT variable because it isn’t needed anymore because of the new way how vovk dev works.
  • JSON divider for streams is a new line instead of an ugly hard-coded string.

CLI

  • Transfer CLI to TS.
  • Move to a separate package.

vovk init

NEW

… vovk-init package

vovk new

NEW

vovk dev

NEW

vovk-zod v1

It wasn’t too fun to use vovk-zod because it required to provide a model to a decorator and a type to a method separately because decorators aren’t able to change class signature.

❌ Old syntax
import { z } from 'zod'; import vovkZod from 'vovk-zod'; // ... other imports ... const UpdateUserModel = z.object({ name: z.string(), email: z.email() }).strict(); const UpdateUserQueryModel = z.object({ id: z.uuid() }).strict(); export default class UserController { @put.auto() @vovkZod(UpdateUserModel, UpdateUserQueryModel) static updateUser(req: VovkRequest<z.infer<typeof UpdateUserModel>, z.infer<typeof UpdateUserQueryModel>>) { // ... } }

This problem has been solved by introducing the withZod function that allows to use Zod validation in a more elegant way.

βœ… New syntax
import { prefix, put } from 'vovk'; import { withZod } from 'vovk-zod'; import { UpdateUserModel, UpdateUserQueryModel } from './models'; @prefix('users') export default class UserController { @put() static updateUser = withZod( z.object({ name: z.string(), email: z.email() }).strict(), z.object({ id: z.uuid() }).strict(), async (req) => { const { name, email } = await req.json(); return { success: true, user: { name, email }, }; } ); }

req object type is retrieved from the provided models.

vovkZod default export has been removed.

vovk-validate-client-ajv  package has been made in order to provide easier way to create custom validation libraries that emit JSON Schema. It’s used by vovk-zod/validateOnClient.

vovk-yup v0

NEW

vovk-dto v0

Vovk.ts is heavily inspired by NestJS  that heavily uses so-called DTOs  for data validation. Previous versions of Vovk.ts supported only Zod  validation without a way to use this idea that perfectly fits service-controller pattern. vovk-dto introduces the new way of server-side and client-side validation using class-validator  and class-transformer  that don’t require reflect-metadata  to be used.

import { prefix, post } from 'vovk'; import { withDto } from 'vovk-dto'; import { CreateUserDto } from './dto'; @prefix('users') export default class UserController { @post() static createUser = withDto(CreateUserDto, async (req) => { const { name, email } = await req.json(); return { success: true, user: { name, email }, }; }); }

withDto is also patching req.vovk.body and req.vovk.query properties in order to convert the input data to the DTO instance.

// ... import { CreateUserDto, CreateUserQueryDto } from './dto'; export default class UserController { @post() static createUser = withDto(CreateUserDto, CreateUserQueryDto, async (req) => { const body = await req.vovk.body(); const query = req.vovk.query(); console.log(body instanceof CreateUserDto); // true console.log(query instanceof CreateUserQueryDto); // true // ... }); }

Since DTOs aren’t serializable, the validation data is not emitted to the schema. Instead, the schema receives { isDto: true } flag as validation property. In order to validate the input data on the client side, you need to convert the it to DTO instances manually with class-transformer .

import { UserRPC } from 'vovk-client'; import { plainToClass } from 'class-transformer'; import validateOnClient from 'vovk-dto/validateOnClient'; import { CreateUserDto, CreateUserQueryDto } from './dto'; // ... const user = await UserRPC.createUser({ body: plainToClass(CreateUserDto, body), query: plainToClass(CreateUserQueryDto, query), validateOnClient, });

validateOnClient is optional if config has validateOnClient set to "vovk-dto/validateOnClient".

TODO dto-mapped-types, reflect-metadata

Last updated on