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 toapiRoot
. - Rename
StreamResponse
toJSONLinesResponse
. - 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
andVovkConfig
types to vovk-cli package. - Completely removed Web Worker features.
New features
req.vovk
object withbody()
,query()
,meta()
andform()
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
andvalidateOnClient
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.
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.
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