Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decorator to return a 404 in a Nest controller

Tags:

I'm working on a backend using NestJS, (which is amazing btw). I have a 'standard get a single instance of an entity situation' similar to this example below.

@Controller('user') export class UserController {     constructor(private readonly userService: UserService) {}     ..     ..     ..     @Get(':id')     async findOneById(@Param() params): Promise<User> {         return userService.findOneById(params.id);     } 

This is incredibly simple and works - however, if the user does not exist, the service returns undefined and the controller returns a 200 status code and an empty response.

In order to make the controller return a 404, I came up with the following:

    @Get(':id')     async findOneById(@Res() res, @Param() params): Promise<User> {         const user: User = await this.userService.findOneById(params.id);         if (user === undefined) {             res.status(HttpStatus.NOT_FOUND).send();         }         else {             res.status(HttpStatus.OK).json(user).send();         }     }     ..     .. 

This works, but is a lot more code-y (yes it can be refactored).

This could really use a decorator to handle this situation:

    @Get(':id')     @OnUndefined(404)     async findOneById(@Param() params): Promise<User> {         return userService.findOneById(params.id);     } 

Anyone aware of a decorator that does this, or a better solution than the one above?

like image 758
Rich Duncan Avatar asked Apr 07 '18 16:04

Rich Duncan


People also ask

How do I return a Nestjs 404?

Make NestJs returns 404 when EntityNotFoundError exception is thrown. When using findOrFail() or findOneOrFail() from typeORM, a 500 error is returned if there is no entity (EntityNotFoundError). To make it returns a 404, use an exception filter as described in https://docs.nestjs.com/exception-filters .

How do I return my nest JS status code?

As mentioned, the response status code is always 200 by default, except for POST requests which are 201. We can easily change this behavior by adding the @HttpCode(...) decorator at a handler level. Hint Import HttpCode from the @nestjs/common package.


1 Answers

The shortest way to do this would be

@Get(':id') async findOneById(@Param() params): Promise<User> {     const user: User = await this.userService.findOneById(params.id);     if (user === undefined) {         throw new BadRequestException('Invalid user');     }     return user; } 

There is no point in decorator here because it would have the same code.

Note: BadRequestException is imported from @nestjs/common;

Edit

After some time with, I came with another solution, which is a decorator in the DTO:

import { registerDecorator, ValidationArguments, ValidationOptions, ValidatorConstraint } from 'class-validator'; import { createQueryBuilder } from 'typeorm';  @ValidatorConstraint({ async: true }) export class IsValidIdConstraint {      validate(id: number, args: ValidationArguments) {         const tableName = args.constraints[0];         return createQueryBuilder(tableName)             .where({ id })             .getOne()             .then(record => {                 return record ? true : false;             });     } }  export function IsValidId(tableName: string, validationOptions?: ValidationOptions) {     return (object, propertyName: string) => {         registerDecorator({             target: object.constructor,             propertyName,             options: validationOptions,             constraints: [tableName],             validator: IsValidIdConstraint,         });     }; }  

Then in your DTO:

export class GetUserParams {     @IsValidId('user', { message: 'Invalid User' })     id: number; } 

Hope it helps someone.

like image 111
Valera Avatar answered Oct 07 '22 01:10

Valera