Skip to content

exception filters

John Biundo edited this page Aug 21, 2019 · 2 revisions

Exception Filters Chapter

With this chapter, if you want to follow along, check out the exception-filters-start branch and go to the following along section.

If you just want a final version of the project as of the end of the chapter, check out the exception-filters-end branch, and proceed to the Upon completion section.

Following along

Exception filters part 1 section (default handling)

As described in the docs, here, if you throw an exception from your code, it's caught by the built-in exception layer provided by Nest. To see this in action, add the following route to src/cats/cats.controller.ts:

@Controller('cats')
export class CatsController {
  @Get('bad')
  badRoute() {
    throw new Error('kaboom');
  }
  ...
}
HTTPie request to test default exception handler

http GET :3000/cats/kaboom

Base exceptions section

As described in the docs, here, you can throw a Nest built-in HttpException. Go ahead and update the CatsController as shown in the fully overridden response body example (the code below):

@Get()
async findAll() {
  throw new HttpException({
    status: HttpStatus.FORBIDDEN,
    error: 'This is a custom message',
  }, 403);
}
HTTPie request to test custom exception

http GET :3000/cats

Exception filters section (creating an exception filter)

As explained in the docs, here, go ahead and create the HttpExceptionFilter class in a file called src/common/filters/http-exception.filter.ts. Just as with the logging middleware, we'll do this in the src/common folder, and we'll create a filters folder to contain the class. The folder structure should now look like:

nest-cats
└───src
    └───cats
    │   └───dto
    │   └───interfaces
    └───common
        └───filters
        └───middleware

Binding exception filter

Similar to what's explained in the docs, here, let's bind the exception. Varying slightly from the docs to ease testing, let's create a new route for testing the exception filter.

We'll add an endpoint GET /httpexcep and bind the exception filter to that route. You can use either the instance (e.g., @UseFilters(new HttpExceptionFilter())) or the class (e.g., @UseFilters(HttpExceptionFilter)). The docs explain the trade-offs.

Here's what src/cats/cats.controller.ts should look like now:

import {
  Controller,
  Get,
  Post,
  Param,
  Body,
  Put,
  Delete,
  HttpStatus,
  HttpException,
  UseFilters,
} from '@nestjs/common';
import { CreateCatDto, UpdateCatDto } from './dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';
import { HttpExceptionFilter } from '../common/filters/http-exception.filter';

@Controller('cats')
export class CatsController {
  constructor(private readonly catsService: CatsService) {}

  @Get('kaboom')
  badRoute() {
    throw new Error('kaboom');
  }

  @Post()
  async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
  }

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }

  // route to test our HttpExceptionFilter
  @Get('httpexcep')
  @UseFilters(HttpExceptionFilter)
  async getExcep() {
    throw new HttpException(
      {
        status: HttpStatus.FORBIDDEN,
        error: 'This is a custom message',
      },
      403
    );
  }

  @Get(':id')
  findOne(@Param('id') id: string) {
    return `This action returns a #${id} cat`;
  }

  @Put(':id')
  update(@Param('id') id: string, @Body() updateCatDto: UpdateCatDto) {
    return `This action updates a #${id} cat`;
  }

  @Delete(':id')
  remove(@Param('id') id: string) {
    return `This action removes a #${id} cat`;
  }
}

Upon completion

You now have an exception handler defined for the GET /cats route. You can either proceed using your code, or if you've run into any issues, you can checkout the exception-filters-end branch to get caught up with the code as of the end of this chapter.

You should now be able to test the app with some REST requests.

HTTPie request demonstrating the exception filter

Test the exception filter by making a request to GET /cats with:

http GET :3000/cats/httpexcep

Notice that the HttpExceptionFilter is handling this exception, providing a standard response that looks like the following, replacing our custom exception message thrown in the route handler:

{
  "path": "/cats/httpexcep",
  "statusCode": 403,
  "timestamp": "2019-08-25T16:06:40.158Z"
}

What's next

Next up is the Pipes chapter.

Clone this wiki locally