vovk-zod
TypeScript icon, indicating that this package has built-in type declarations

0.1.2 • Public • Published

  plus plus

vovk-zod

Isomorphic Zod validation for Vovk.ts controllers on server and client

npm version TypeScript Build status

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 {
    private static userService = UserService;

    @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 this.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: 'john@example.com' },
            // 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 customization docs for more info.

Hint: To produce less variables you can also declare Zod models as static (with an optional private prefix) class members of the controller to access them within the @vovkZod decorator and VovkRequest.

// ...

export default class UserController {
    private static userService = UserService;

    private static UpdateUserModel = z.object({
        name: z.string(),
        email: z.string(),
    }).strict();

    private static UpdateUserQueryModel = z.object({
        id: z.string(),
    }).strict();

    @put()
    @vovkZod(UserController.UpdateUserModel, UserController.UpdateUserQueryModel)
    static updateUser(
        req: VovkRequest<
            z.infer<typeof UserController.UpdateUserModel>, 
            z.infer<typeof UserController.UpdateUserQueryModel>
        >
    ) {
       // ...
    }
}

The TypeScript compiler processes decorators at compile time and doesn't enforce private or protected access restrictions for members used within decorators in the same class. This behavior allows for more flexible class meta-programming patterns, which decorators aim to facilitate.

Working with FormData

The library doesn't support FormData validation, but you can still validate query by setting body validation to null.

// ...

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');

        // ...
    }
}

How it works

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.

Readme

Keywords

Package Sidebar

Install

npm i vovk-zod

Weekly Downloads

1

Version

0.1.2

License

MIT

Unpacked Size

84.5 kB

Total Files

7

Last publish

Collaborators

  • finom