Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Pipes

A pipe is a class that an argument passes through before it reaches the controller method. A pipe can transform the value (the string "5" into the number 5) or check it and reject the request with a 400 error. The ValidationPipe from the previous lesson is a pipe too.

The built-in ParseIntPipe

Address parameters arrive as strings. ParseIntPipe turns a string into an integer:

// src/posts/posts.controller.ts
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
import { PostsService } from './posts.service';
 
@Controller('posts')
export class PostsController {
  constructor(private readonly postsService: PostsService) {}
 
  @Get(':id')
  findOne(@Param('id', ParseIntPipe) id: number) {
    return this.postsService.findOne(id);
  }
}

The pipe is the second argument of the decorator. Now id is a real number, and Number(id) is no longer needed. Open /posts/abc — instead of an empty response you get a 400 error saying Validation failed (numeric string is expected).

A default value

DefaultValuePipe substitutes a value when the parameter is missing. Pipes run from left to right:

// src/posts/posts.controller.ts
import { DefaultValuePipe, Get, ParseIntPipe, Query } from '@nestjs/common';
 
@Get()
findAll(@Query('page', new DefaultValuePipe(1), ParseIntPipe) page: number) {
  return { page };
}

/posts returns {"page":1}, and /posts?page=3 returns {"page":3}.

Built-in pipes

PipeWhat it does
ParseIntPipeString to integer
ParseFloatPipeString to decimal number
ParseBoolPipe"true" and "false" to a boolean
ParseUUIDPipeChecks that the string is a UUID
ParseEnumPipeChecks that the value belongs to an enum
DefaultValuePipeSubstitutes a default value
ValidationPipeChecks an object against DTO rules

Your own pipe

A page number cannot be zero or negative. Create a pipe:

nest g pipe common/pipes/positive-int --flat
// src/common/pipes/positive-int.pipe.ts
import { BadRequestException, Injectable, PipeTransform } from '@nestjs/common';
 
@Injectable()
export class PositiveIntPipe implements PipeTransform {
  transform(value: string): number {
    const number = Number(value);
 
    if (!Number.isInteger(number) || number < 1) {
      throw new BadRequestException('A positive integer is expected');
    }
 
    return number;
  }
}

The pipe implements the PipeTransform interface: transform() receives the value and returns what ends up in the argument. A thrown BadRequestException becomes a 400 response.

A custom pipe is attached the same way as built-in ones:

// src/posts/posts.controller.ts
import { PositiveIntPipe } from '../common/pipes/positive-int.pipe';
 
@Get(':id')
findOne(@Param('id', PositiveIntPipe) id: number) {
  return this.postsService.findOne(id);
}

The address /posts/0 returns 400 with the message "A positive integer is expected".

Common mistake

Without a pipe, the number type on an argument changes nothing: TypeScript does not convert data at runtime, and id still holds a string. The comparison post.id === id then never matches, and the service returns an empty response. If an argument is declared as a number, it needs ParseIntPipe or transform: true in ValidationPipe.

Thanks for reading!

Donate to the site — we work hard for you.