diff --git a/README.md b/README.md index 406c3db6..e636be93 100644 --- a/README.md +++ b/README.md @@ -691,7 +691,30 @@ There are set of prepared errors you can use: * NotFoundError * UnauthorizedError -You can also create and use your own errors by extending `HttpError` class. + +You can also create and use your own errors by extending `HttpError` class. +To define the data returned to the client, you could define a toJSON method in your error. + +```typescript +class DbError extends HttpError { + public operationName: string; + public args: any[]; + + constructor(operationName: string, args: any[] = []) { + super(500); + Object.setPrototypeOf(this, DbError.prototype); + this.operationName = operationName; + this.args = args; // can be used for internal logging + } + + toJSON() { + return { + status: this.httpCode, + failedOperation: this.operationName + } + } +} +``` #### Enable CORS diff --git a/src/driver/BaseDriver.ts b/src/driver/BaseDriver.ts index 833a1bdc..26c298db 100644 --- a/src/driver/BaseDriver.ts +++ b/src/driver/BaseDriver.ts @@ -150,6 +150,9 @@ export abstract class BaseDriver { if (!this.isDefaultErrorHandlingEnabled) return error; + if (typeof error.toJSON === "function") + return error.toJSON(); + let processedError: any = {}; if (error instanceof Error) { const name = error.name && error.name !== "Error" ? error.name : error.constructor.name; diff --git a/test/functional/express-error-handling.spec.ts b/test/functional/express-error-handling.spec.ts index 62ec7626..37d374ac 100644 --- a/test/functional/express-error-handling.spec.ts +++ b/test/functional/express-error-handling.spec.ts @@ -6,6 +6,7 @@ import {Middleware} from "../../src/decorator/Middleware"; import {UseAfter} from "../../src/decorator/UseAfter"; import {ExpressErrorMiddlewareInterface} from "../../src/driver/express/ExpressErrorMiddlewareInterface"; import {NotFoundError} from "../../src/http-error/NotFoundError"; +import {HttpError} from "../../src/http-error/HttpError"; const chakram = require("chakram"); const expect = chakram.expect; @@ -54,6 +55,25 @@ describe("express error handling", () => { } + class ToJsonError extends HttpError { + public publicData: string; + public secretData: string; + + constructor(httpCode: number, publicMsg?: string, privateMsg?: string) { + super(httpCode); + Object.setPrototypeOf(this, ToJsonError.prototype); + this.publicData = publicMsg || "public"; + this.secretData = privateMsg || "secret"; + } + + toJSON() { + return { + status: this.httpCode, + publicData: `${this.publicData} (${this.httpCode})` + } + } + } + @JsonController() class ExpressErrorHandlerController { @@ -97,6 +117,11 @@ describe("express error handling", () => { return "1234"; } + @Get("/stories") + stories() { + throw new ToJsonError(503, "sorry, try it again later", "impatient user"); + } + } }); @@ -154,4 +179,15 @@ describe("express error handling", () => { }); }); + it("should process JsonErrors by their toJSON method if it exists", () => { + return chakram + .get("http://127.0.0.1:3001/stories") + .then((response: any) => { + expect(response).to.have.status(503); + expect(response.body).to.have.property("status").and.equals(503); + expect(response.body).to.have.property("publicData").and.equals("sorry, try it again later (503)"); + expect(response.body).to.not.have.property("secretData"); + }); + }); + }); \ No newline at end of file