1

hi i have this middlware for handle errors on my project:

  private initializeErrorHandling() {
    this.app.use(
      (err: Error, request: Request, response: Response, _: NextFunction) => {
        if (err instanceof CustomExternalError) {
          return response.status(err.statusCode).json(err.message);
        }

        console.log(err);

        return response.status(500).json({
          status: 'error',
          message: 'Internal server error',
        });
      },
    );
  }

I use the following controller structure:

@singleton()
export class DepartamentController implements IController {
  private router: Router;
  private path: string;
  private services: DepartamentServices;
  constructor() {
    this.path = '/departament';
    this.router = Router();
    this.services = container.resolve(DepartamentServices);
    this.initializeRoutes();
  }
  private initializeRoutes() {
    this.router.post(`${this.path}/create`, this.test.bind(this));
  }
  getPath(): string {
    return this.path;
  }
  getRouter(): Router {
    return this.router;
  }

  private async test() {
    this.services.test();
  }

}

and this is my role in my service where I invoke my error:

 public async test() {
    throw new CustomExternalError(
      {
        message: 'Validation Failed',
        errors: [
          {
            resource: 'Departament',
            field: 'a',
            code: 'unprocessable',
          },
        ],
      },
      responseCodes.UNPROCESSABLE_ENTITY,
    );
  }

this is my custom error:

export class CustomExternalError {
  constructor(public error: responseError, public statusCode: responseCodes) {
    this.error;
    this.statusCode;
  }
}

and I add my routes to my express server with the following function:

  private initializeRoutes() {
    container.resolveAll<IController>('Controller').forEach(controller => {
      this.app.use('/', controller.getRouter());
    });
  }

My route works normally, but for some reason when throwing the error it doesn't call my middlware error handle, but if I call the error on my controller it works normally

i got this error :

(node:8704) UnhandledPromiseRejectionWarning: #<CustomExternalError>
(Use `node --trace-warnings ...` to show where the warning was created)
(node:8704) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:8704) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
1
  • This comment might be unhelpful as I am no expert in express, but UnhandledPromiseRejectionWarning is normally happening when a promise throws/rejects, and you do not have a .catch-statement. Not sure if the framework should do this for you, but perhaps returning the promise produced by the test-method will help you out? When you throw inside an async method, it becomes a failing promise, so not handling it's error creates a new error. In other words, perhaps return this.services.test(); in DepartamentController#test will resolve the issue. Commented Aug 3, 2020 at 12:35

1 Answer 1

2

You test method is async, so when it throws anything it needs to be handled inside that promise's catch block otherwise you'll have that promise rejection warning. So, you may want to create a middleware that catch those unhandled promise rejections and pass them to your errors handler middleware:

You can either use a wrapper method that handles that:

const asynchHandler = fn => (...args) => fn(args).catch(args[2])

or this package: express-async-handler.

Then in your controller:

  private initializeRoutes() {
    this.router.post(`${this.path}/create`, asynchHandler(this.test.bind(this)));
  }

Or just handle your promise rejection and explicitly call the midleware

private async test(request: Request, response: Response, next: NextFunction) {
  try {
     ...
     await this.service.test(...)
     ...
   } catch (err: CustomExternalError) {
     next(next)
   }
 }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.