diff --git a/examples/express-example-with-default-settings/package.json b/examples/express-example-with-default-settings/package.json index 953fbe3..be7468f 100644 --- a/examples/express-example-with-default-settings/package.json +++ b/examples/express-example-with-default-settings/package.json @@ -21,7 +21,7 @@ "@nestjs/common": "^11.0.4", "@nestjs/core": "^11.0.4", "@nestjs/platform-express": "^11.0.4", - "nest-problem-details-filter": "file:../../libs/nest-problem-details-filter/nest-problem-details-filter-1.0.0.tgz", + "nest-problem-details-filter": "file:../../libs/nest-problem-details-filter/nest-problem-details-filter-1.0.1.tgz", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" }, diff --git a/examples/fastify-example-with-default-settings/package.json b/examples/fastify-example-with-default-settings/package.json index 041ae13..faaa66f 100644 --- a/examples/fastify-example-with-default-settings/package.json +++ b/examples/fastify-example-with-default-settings/package.json @@ -21,7 +21,7 @@ "@nestjs/common": "^11.0.4", "@nestjs/core": "^11.0.4", "@nestjs/platform-fastify": "^11.0.4", - "nest-problem-details-filter": "file:../../libs/nest-problem-details-filter/nest-problem-details-filter-1.0.0.tgz", + "nest-problem-details-filter": "file:../../libs/nest-problem-details-filter/nest-problem-details-filter-1.0.1.tgz", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" }, diff --git a/libs/nest-problem-details-filter/package.json b/libs/nest-problem-details-filter/package.json index 7057e08..318830e 100644 --- a/libs/nest-problem-details-filter/package.json +++ b/libs/nest-problem-details-filter/package.json @@ -1,6 +1,6 @@ { "name": "nest-problem-details-filter", - "version": "1.0.0", + "version": "1.0.1", "license": "MIT", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -18,8 +18,8 @@ "homepage": "https://github.com/Fcmam5/nest-http-problem-details#readme", "scripts": { "build": "nest build", - "prepack": "rm -rf dist && npm run build", - "prepublish": "rm -rf dist && npm run build", + "prepack": "shx rm -rf dist && npm run build", + "prepublish": "shx rm -rf dist && npm run build", "format": "prettier --write \"src/**/*.ts\"", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "lint:fix": "npm run lint -- --fix", @@ -48,6 +48,7 @@ "prettier": "^3.4.2", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", + "shx": "^0.3.4", "source-map-support": "^0.5.21", "ts-jest": "^29.2.5", "ts-loader": "^9.5.2", diff --git a/libs/nest-problem-details-filter/src/filters/http-exception.filter.spec.ts b/libs/nest-problem-details-filter/src/filters/http-exception.filter.spec.ts index 8ef40a5..9656b6a 100644 --- a/libs/nest-problem-details-filter/src/filters/http-exception.filter.spec.ts +++ b/libs/nest-problem-details-filter/src/filters/http-exception.filter.spec.ts @@ -44,6 +44,23 @@ const mockHttpAdatperHost = { }, } as unknown as Pick; +// Example business error +class BusinessErrorException extends HttpException { + constructor(message: string, detail?: string, instance?: string) { + super( + { + message, + error: { + type: 'business-error', + detail, + instance, + }, + }, + HttpStatus.BAD_REQUEST, + ); + } +} + describe('HttpExceptionFilter', () => { let filter: HttpExceptionFilter; @@ -199,6 +216,65 @@ describe('HttpExceptionFilter', () => { }); }); + describe('BusinessErrorException', () => { + it('should map BusinessErrorException with custom type', () => { + const status = HttpStatus.BAD_REQUEST; + const message = 'A business error occurred'; + + const expectation: IProblemDetail = { + title: message, + status, + type: 'http://fcmam5.me/problems/business-error', // Include base URI + }; + + filter.catch(new BusinessErrorException(message), mockArgumentsHost); + + assertResponse(status, expectation); + }); + + it('should map BusinessErrorException with custom type and additional details', () => { + const status = HttpStatus.BAD_REQUEST; + const message = 'A business error occurred with details'; + const detail = 'Additional error details'; + + const expectation: IProblemDetail = { + title: message, + status, + type: 'http://fcmam5.me/problems/business-error', // Include base URI + detail, + }; + + filter.catch( + new BusinessErrorException(message, detail), + mockArgumentsHost, + ); + + assertResponse(status, expectation); + }); + + it('should map BusinessErrorException with custom type, details, and instance', () => { + const status = HttpStatus.BAD_REQUEST; + const message = 'A business error occurred with details and instance'; + const detail = 'Additional error details'; + const instance = 'instance-123'; + + const expectation: IProblemDetail = { + title: message, + status, + type: 'http://fcmam5.me/problems/business-error', // Include base URI + detail, + instance, + }; + + filter.catch( + new BusinessErrorException(message, detail, instance), + mockArgumentsHost, + ); + + assertResponse(status, expectation); + }); + }); + describe.each([ ['HttpAdapterHost', mockHttpAdatperHost as HttpAdapterHost], ['HttpAdapter', mockHttpAdapter as HttpAdapterHost['httpAdapter']], diff --git a/libs/nest-problem-details-filter/src/filters/http-exception.filter.ts b/libs/nest-problem-details-filter/src/filters/http-exception.filter.ts index 982cf87..35c9110 100644 --- a/libs/nest-problem-details-filter/src/filters/http-exception.filter.ts +++ b/libs/nest-problem-details-filter/src/filters/http-exception.filter.ts @@ -40,9 +40,7 @@ export class HttpExceptionFilter implements ExceptionFilter { const ctx = host.switchToHttp(); const response = ctx.getResponse(); const status = exception.getStatus(); - const errorResponse = exception.getResponse() as - | string - | IExceptionResponse; + const errorResponse = exception.getResponse() as string | IErrorDetail; let title: string; let detail; @@ -57,7 +55,8 @@ export class HttpExceptionFilter implements ExceptionFilter { detail = errorResponse.error; } else { if (errorResponse.error) { - type = errorResponse.error.error?.type; + type = errorResponse.error.type; + detail = errorResponse.error.detail; objectExtras = { ...errorResponse.error, }; @@ -83,11 +82,3 @@ export class HttpExceptionFilter implements ExceptionFilter { return this.defaultHttpErrors[status]; } } - -interface IExceptionResponse { - error?: string | IErrorDetail; - message: string; - type?: string; - instance?: string; - statusCode: number; -}