Fixing validation error in NestJS when using forbidUnknwonValues

Published on October 12, 2021

Tagged: #nestjs

Follow me on twitter for more posts like this

If you get unexplained validation errors (http status 400) when calling a NestJS api you might want to check your Query() parameters. Parsing and validating these the wrong way can cause issues.

Parsing Query parameters in NestJs

There are two ways to parse query strings in Nest Js. You can parse each variable separately or parse an object. Complex parameters cause issues when parsing from query strings. I would always recommend parsing via an object if you use any kind of non-string parameters.

e.g.

@Controller('myController')
export class MyControllerController {
  @Get()
  async myMethod(
    @Query('param1') param1?: string,
    @Query('param2', new ParseArrayPipe({ items: String, optional: true }))
    param2?: string[]
  ): Promise<void> {}
}

The param2 there will break forbidUnknownValues. Class validator can’t parse it correctly.

Instead you can define an object that describes all the parameters. Define the required transforms and tell nest to run both validation and transformation on the query string to get the right values out.

Create a model that describes the parameters.

import { Type, Transform } from 'class-transformer'
import { IsArray, IsDate, IsDefined, IsEnum, IsOptional } from 'class-validator'

export default class QueryParams {
  @IsString()
  @IsOptional()
  public param1!: string

  @IsOptional()
  @IsArray()
  @IsString({ each: true })
  @Type(() => String)
  @Transform((value: string) => value.split(','))
  public param2?: string[]
}

and then change the controller to use this model instead of individual query string parameters.

@Controller('myController')
export class MyControllerController {
  @Get()
  async myMethod(
    @Query(new ValidationPipe({ transform: true })) allQueryParams: QueryParams
  ): Promise<void> {}
}

Conclusion

You should be able to use the forbidUnknownValues setting in the validation pipe configuration as expected now. In general once I have more than 2-3 query parameters in an api method I think it’s easier to use a query object.

Darragh ORiordan

Hi! I'm Darragh ORiordan.

I live and work in Sydney, Australia building supporting happy teams that create high quality software for the web.

I also make tools for busy developers! Do you have a new M1 Mac to setup? Have you ever spent a week getting your dev environment just right?

My DevShell tooling will save you 30+ hours configuring your dev environment with all the best modern tools. Get it here

https://darraghoriordan.gumroad.com/l/devshell


Read more articles like this one...

List of article summaries

#nestjs

A Nest JS Pipeline Cheatsheet

I’m always checking the NestJS documentation to read what a Middleware Vs Interceptor is and I could never remember the order that the different NestJS pipeline elements are called in.

So I made this cheatsheet for myself so I had something to refer to.

#nestjs

Using a dynamic DTO property in a NestJS API

NestJS is designed around using strictly typed properties on models but sometimes it’s useful (and fast!) to allow dynamic types on properties and just store some business domain data as a dynamic serialized blob.

This is the serialized LOB method recommended by Martin Fowler (https://martinfowler.com/eaaCatalog/serializedLOB.html).

Here is how you can have a LOB in a NestJS REST Api with type safety and support for OpenAPI definitions.

#nestjs

Automatically setting empty arrays instead of undefined on typeorm entities

If you have an array on an entity model in typeorm you will have to handle the response when there are no items available to put in the array.

In my application I return the entity model directly for GET requests and I like having arrays as empty instead of undefined properties.

By default typeorm will not set the property to [] so it will be undefined.

Here is how to set an array property to have an empty array instead of undefined.