Isomorphic Zod validation for Vovk.ts controllers on server and client
vovk-zod exports vovkZod
decorator fabric that validates request body and incoming query string with Zod models.
// /src/models/user/UserController.ts
import { z } from 'zod';
import vovkZod from 'vovk-zod';
import { put, type VovkRequest } from 'vovk';
import UserService from './UserService';
const UpdateUserModel = z.object({
name: z.string(),
email: z.string(),
}).strict();
const UpdateUserQueryModel = z.object({
id: z.string(),
}).strict();
export default class UserController {
@put()
@vovkZod(UpdateUserModel, UpdateUserQueryModel)
static updateUser(
req: VovkRequest<z.infer<typeof UpdateUserModel>, z.infer<typeof UpdateUserQueryModel>>
) {
const { name, email } = await req.json();
const id = req.nextUrl.searchParams.get('id');
return UserService.updateUser(id, { name, email });
}
}
'use client';
import React from 'react';
import { UserController } from 'vovk-client';
const MyPage = () => {
useEffect(() => {
void UserController.updateUser({
query: { id: '696969' },
body: { name: 'John Doe', email: '[email protected]' },
// optionally, disable client validation for debugging purpose
disableClientValidation: true,
}).then(/* ... */);
}, []);
return (
// ...
)
}
export default MyPage;
When vovk-zod is installed zodValidateOnClient is enabled by default as validateOnClient
config option to validate incoming reqests on the client-side. Please check decorators docs for more info.
The library doesn't support FormData
validation, but you can still validate query by setting body validation to null
. At the same time VovkRequest
should get FormData
type as the first generic parameter in order to make types of vovk-client infer body as expected.
// ...
export default class HelloController {
@post()
@vovkZod(null, z.object({ something: z.string() }).strict())
static postFormData(req: VovkRequest<FormData, { something: string }>) {
const formData = await req.formData();
const something = req.nextUrl.searchParams.get('something');
// ...
}
}
The library (as well as Vovk.ts itself) is built thanks to fantastic job made by other people.
- When
@vovkZod
is initialised, it converts Zod schemas to JSON Schemas with zod-to-json-schema and makes metadata handler to receive it as client validation object. @vovkZod
performs Zod validation on server-side.- When clientized controller method gets called
zodValidateOnClient
performs validation on client-side with Ajv. Since client-side and server-side validation is implemented by different libraries, error messages are going to be different.