UNPKG

nestjs-typebox

Version:

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

77 lines (65 loc) 2.84 kB
import { Static, TObject, TProperties, Type } from '@sinclair/typebox'; import { TypeCheck, TypeCompiler } from '@sinclair/typebox/compiler'; import { tryCoerceToNumber } from './util'; import { TypeboxValidationException } from './exceptions'; export interface TypeboxDto<T extends TProperties, R = Static<TObject<T>>> { new (): R; isTypeboxDto: true; typeboxSchema: TObject<T>; validator: TypeCheck<TObject<T>> | undefined; toJsonSchema(): TObject<T>; beforeValidate(data: unknown): unknown; validate(data: unknown): unknown; transform(data: Static<TObject<T>>): R; } export interface DtoOptions<T extends TProperties, R = Static<TObject<T>>> { transform?: (data: Static<TObject<T>>) => R; coerceTypes?: boolean; stripUnknownProps?: boolean; } export abstract class TypeboxModel<T extends TProperties> { abstract readonly data: T; } export const createTypeboxDto = <T extends TProperties, R = Static<TObject<T>>>(schema: TObject<T>, options?: DtoOptions<T, R>) => { class AugmentedTypeboxDto extends TypeboxModel<Static<TObject<T>>> { public static isTypeboxDto = true; public static schema = schema; public static options = options; public static validator: TypeCheck<TObject<T>> | undefined; public static toJsonSchema() { return Type.Strict(this.schema); } public static beforeValidate(data: Record<string, unknown>): unknown { const result = this.options?.stripUnknownProps ? ({} as Record<string, unknown>) : data; if (this.options?.coerceTypes || this.options?.stripUnknownProps) { const schema = this.toJsonSchema(); for (const [prop, def] of Object.entries(schema.properties)) { if (data[prop] === undefined) continue; switch (def.type) { case 'number': result[prop] = tryCoerceToNumber(data[prop]); break; default: result[prop] = data[prop]; } } } return result; } public static validate(data: unknown): void { if (!this.validator) { this.validator = TypeCompiler.Compile(this.schema); } if (!this.validator.Check(data)) { throw new TypeboxValidationException(this.validator.Errors(data)); } } public static transform(data: Static<TObject<T>>): R { return this.options?.transform?.(data) ?? (data as unknown as R); } constructor(readonly data: Static<TObject<T>>) { super(); } } return AugmentedTypeboxDto as unknown as TypeboxDto<T, R>; };