npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ballerine-nestjs-typebox

v3.0.2-next.11

Published

This library provides helper utilities for writing and validating NestJS APIs using [TypeBox](https://github.com/sinclairzx81/typebox) as an alternative to class-validator/class-transformer. It also includes a patch for @nestjs/swagger allowing OpenAPI ge

Downloads

312

Readme

nestjs-typebox

This library provides helper utilities for writing and validating NestJS APIs using TypeBox as an alternative to class-validator/class-transformer. It also includes a patch for @nestjs/swagger allowing OpenAPI generation to continue working.

Warning

As of 2.x, this library is undergoing active development and will stabilize with the 3.x release. It was decided to drop support for the class-based DTO approach in favor of a pure decorator approach, since the class-based approach made it impossible to validate complex union types.

Installation

npm i nestjs-typebox @sinclair/typebox

Usage

1. Create TypeBox schema

The example below demonstrates a discriminated union type, which was previously incompatible with the class-based DTO approach used in v1. JSON schema fields like "description" will be parsed by the Swagger generator.

import { Type } from '@sinclair/typebox';

export const PetSchemaBase = Type.Object({
    id: Type.Number(),
    name: Type.String({
        description: "The pet's name",
        examples: ['Figaro'],
    }),
    microchip: Type.String(){
        description: 'Secret microchip number. Not sent to client'
    },
});

export const CatSchema = Type.Composite([
    PetSchemaBase,
    Type.Object({
        type: Type.Literal('cat'),
        breed: Type.Union([Type.Literal('shorthair'), Type.Literal('persian'), Type.Literal('siamese')]),
    }),
]);

export const DogSchema = Type.Composite([
    PetSchemaBase,
    Type.Object({
        type: Type.Literal('dog'),
        breed: Type.Union([Type.Literal('shiba-inu'), Type.Literal('poodle'), Type.Literal('dachshund')]),
    }),
]);

export const PetSchema = Type.Union([CatSchema, DogSchema]);
export type Pet = Static<typeof PetSchema>;

2. Decorate controller methods

The example below shows two different decorators and their usage, calling out default configuration. Schemas have all been defined inline for brevity, but could just as easily be defined elsewhere and reused. The primary benefit of using @HttpEndpoint over @Validator is the additional validation enforcing path parameters to be properly defined as request "param" validators. Otherwise, it simply passes through options specified in validate to the underlying @Validator decorator.

import { Type } from '@sinclair/typebox';
import { Validate, HttpEndpoint } from 'nestjs-typebox';

@Controller('pets')
export class PetController {
    constructor(private readonly petService: PetService) {}

    @Get()
    @Validate({
        response: { schema: Type.Array(Type.Omit(PetSchema, ['microchip'])), stripUnknownProps: true },
    })
    async getPets() {
        return this.petService.getPets();
    }

    @Get(':id')
    @Validate({
        // stripUnknownProps is true by default for response validators
        // so this shorthand is equivalent
        response: Type.Omit(PetSchema, ['microchip']),
        request: [
            // coerceTypes is true by default for "param" and "query" request validators
            { name: 'id', type: 'param', schema: Type.Number(), coerceTypes: true },
        ],
    })
    // no need to use @Param() decorator here since the @Validate() decorator will
    // automatically attach a pipe to populate and convert the paramater value
    async getPet(id: number) {
        return this.petService.getPet(id);
    }

    @Post()
    @Validate({
        response: Type.Omit(PetSchema, ['microchip']),
        request: [
            // if "name" not provided, method name will be used
            { type: 'body', schema: Type.Omit(PetSchema, 'id') },
        ],
    })
    async createPet(data: Omit<Pet, 'id'>) {
        return this.petService.createPet(data);
    }

    @HttpEndpoint({
        method: 'PATCH',
        path: ':id',
        validate: {
            response: Type.Omit(PetSchema, ['microchip']),
            request: [
                { name: 'id', type: 'param', schema: Type.Number() },
                { type: 'body', schema: Type.Partial(Type.Omit(PetSchema, ['id'])) },
            ],
        }
    })
    // the order of the controller method parameters must correspond to the order/types of
    // "request" validators, including "required" configuration. Additionally nestjs-typebox will
    // throw at bootup if parameters defined in the "request" validator config don't correspond
    // with the parameters defined in the "path" configuration
    async updatePet(id: number, data: Partial<Omit<Pet, 'id'>>) {
        return this.petService.updatePet(id, data);
    }

    @HttpEndpoint({
        method: 'DELETE',
        path: ':id',
        validate: {
            response: Type.Omit(PetSchema, ['microchip']),
            request: [{ name: 'id', type: 'param', schema: Type.Number() }],
        }
    })
    async deletePet(id: number) {
        return this.petService.deletePet(id);
    }
}

3. Apply patch for OpenAPI/Swagger Support

As of 2.x, it is no longer necessary to register any interceptors/pipes, global or otherwise.

// main.ts

import { Reflector } from '@nestjs/core';
import { patchNestJsSwagger, applyFormats, TypeboxValidationPipe, TypeboxTransformInterceptor } from 'nestjs-typebox';

// provide swagger OpenAPI generator support
patchNestJsSwagger();

// provide custom JSON schema string format support
// currently only "email".
applyFormats();

async function bootstrap() {
    const app = await NestFactory.create(AppModule);

    await app.listen(3000);
    console.log(`Application is running on: ${await app.getUrl()}`);
}

bootstrap();

Credits

Swagger patch derived from https://github.com/risenforces/nestjs-zod

Todo

  • Validate observable support
  • utility to create typebox schemas with CRUD defaults (i.e. SchemaName['response'], SchemaName['update'])
  • include method name in decorator errors
  • support validating entire query object? (instead of individual values)
  • check controller metadata so resolved path can include params specified at the controller level