Skip to content

Commit

Permalink
Merge pull request #159 from conceptadev/feature/exception-filter-val…
Browse files Browse the repository at this point in the history
…idator-support

feat: support validation pipe errors
  • Loading branch information
MrMaz authored May 24, 2024
2 parents 9f89a73 + 21c6979 commit a77a7c4
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 14 deletions.
1 change: 1 addition & 0 deletions packages/nestjs-exception/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@nestjs/core": "^9.0.0",
"@nestjs/testing": "^9.0.0",
"@types/supertest": "^2.0.11",
"class-validator": "^0.13.2",
"supertest": "^6.1.6"
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import {
BadRequestException,
Body,
Controller,
Get,
Param,
ParseIntPipe,
Post,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { DummyDto } from './dummy.dto';
import { CustomNotFoundExceptionFixture } from './exceptions/custom-not-found.exception.fixture';

/**
Expand All @@ -24,6 +29,12 @@ export class AppControllerFixture {
throw new BadRequestException();
}

@UsePipes(new ValidationPipe())
@Post('/bad-validation')
getBadValidation(@Body() value: DummyDto): DummyDto {
return value;
}

@Get(':id')
getErrorNotFound(@Param('id', ParseIntPipe) id: number): void {
throw new CustomNotFoundExceptionFixture(id);
Expand Down
6 changes: 6 additions & 0 deletions packages/nestjs-exception/src/__fixtures__/dummy.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { IsNumber } from 'class-validator';

export class DummyDto {
@IsNumber()
id!: number;
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ describe('Exception (e2e)', () => {
expect(response.body.message).toEqual('Bad Request');
});

it('Should return array of validation errors', async () => {
const response = await supertest(app.getHttpServer())
.post('/test/bad-validation')
.send({ id: 'not a number' });
expect(response.body.statusCode).toEqual(HttpStatus.BAD_REQUEST);
expect(response.body.errorCode).toEqual('HTTP_BAD_REQUEST');
expect(typeof response.body.message).toEqual('object');
expect(response.body.message).toEqual([
'id must be a number conforming to the specified constraints',
]);
});

it('Should return not found', async () => {
const response = await supertest(app.getHttpServer()).get('/test/123');
expect(response.body.errorCode).toEqual('CUSTOM_NOT_FOUND');
Expand Down
25 changes: 12 additions & 13 deletions packages/nestjs-exception/src/filters/exceptions.filter.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,17 @@
import {
ExceptionFilter,
Catch,
ArgumentsHost,
HttpException,
HttpAdapterHost,
} from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
import { Catch, ArgumentsHost, HttpException } from '@nestjs/common';
import { isObject } from '@nestjs/common/utils/shared.utils';
import { ExceptionInterface } from '@concepta/ts-core';
import { ERROR_CODE_UNKNOWN } from '../constants/error-codes.constants';
import { RuntimeException } from '../exceptions/runtime.exception';
import { mapHttpStatus } from '../utils/map-http-status.util';

@Catch()
export class ExceptionsFilter implements ExceptionFilter {
export class ExceptionsFilter implements ExceptionsFilter {
constructor(private readonly httpAdapterHost: HttpAdapterHost) {}

catch(exception: ExceptionInterface, host: ArgumentsHost): void {
// in certain situations `httpAdapter` might not be available in the
// constructor method, thus we should resolve it here.
const { httpAdapter } = this.httpAdapterHost;

const ctx = host.switchToHttp();

// error code is UNKNOWN unless it gets overridden
Expand All @@ -28,16 +21,22 @@ export class ExceptionsFilter implements ExceptionFilter {
let statusCode = 500;

// what will this message be?
let message: string = 'Internal Server Error';
let message: unknown = 'Internal Server Error';

// is this an http exception?
if (exception instanceof HttpException) {
// set the status code
statusCode = exception.getStatus();
// map the error code
errorCode = mapHttpStatus(statusCode);
// get res
const res = exception.getResponse();
// set the message
message = exception.message;
if (isObject(res) && 'message' in res) {
message = res.message;
} else {
message = res;
}
} else if (exception instanceof RuntimeException) {
// its a runtime exception, set error code
errorCode = exception.errorCode;
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4897,7 +4897,7 @@ class-validator@*:
libphonenumber-js "^1.10.14"
validator "^13.7.0"

class-validator@^0.13.0:
class-validator@^0.13.0, class-validator@^0.13.2:
version "0.13.2"
resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.13.2.tgz#64b031e9f3f81a1e1dcd04a5d604734608b24143"
integrity sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==
Expand Down

0 comments on commit a77a7c4

Please sign in to comment.