0

Suppose I have the following async function

export async function someAsyncFunction() {
  const result = await fetchData();
  return result[0].id;
}

In the route I have

router.post(
  '/some-path',
  handleErrorAsync(async (req: Request, resp: Response, _err: Errback) => {
    const data = await someAsyncFunction();
    resp.json(data)
  })
);

And I have error handling functionalities that do

interface ResponseError extends Error {
  statusCode: number;
}

// Middleware to respond with an error when error caught
export function handleError(
  err: ResponseError,
  _req: Request,
  resp: Response,
  _next: NextFunction
) {
  if (err) {
    resp.status(err.statusCode || 500).json(err);
  }
}

export const handleErrorAsync = (func: Function) => (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  func(req, res, next).catch((error: Error) => {
    next(error);
  });
};

So this works fine if for example fetchData has an error response object, but this fails to print error objects when the error is a regular javascript error and instead it just prints {} with 500 error.

For example in this line return result[0].id; if the result is empty ([]), then this would throw TypeError, which will be caught by the handleError middleware, but then the .json(err) part will show only {}

Is there a way I can get both the servers errors (which are working correctly) and the internal server errors with that same middleware?

AngularDebutant
  • 1,436
  • 5
  • 19
  • 41

4 Answers4

1

res.json do JSON.parse which returns an empty object {}.

I can suggest destructuring the err body.

 resp.status(err.statusCode || 500).json({message:err.message, error:err});

This will give you a message for every Native Error

JustRaman
  • 1,101
  • 9
  • 11
1

You could extend the toJSON method of Error.

let a = new Error("hi")

console.log(JSON.stringify(a))

Error.prototype.toJSON = function () {
    const alt = {};
    // get all property
    Object.getOwnPropertyNames(this).forEach((key) => {
        alt[key] = this[key];
    });

    // only get message property
    // alt["message"] = this["message"]
    return alt;
}

console.log(JSON.stringify(a))

Then just call res.json(error), and you'll get the property of Error.
Because when you call res.json(parameter), express will trigger the toJSON method of parameter. You could read more in Is it not possible to stringify an Error using JSON.stringify? .
But, I recommend only expose the "message" property in toJSON method.

Jack Yu
  • 2,190
  • 1
  • 8
  • 14
  • Thanks for this answer, and for the link which led me to use https://www.npmjs.com/package/serialize-error and it fixed the problem! – AngularDebutant Dec 10 '20 at 16:05
0

I would suggest using res.send() in the error handler like

return res.status(500).send(err.message);

Jithin Zachariah
  • 313
  • 3
  • 13
0

I fixed the issue using https://www.npmjs.com/package/serialize-error

import { serializeError } from 'serialize-error';

  if (err) {
    resp
      .status(err.statusCode || 500)
      .json(serializeError(err));
  }
AngularDebutant
  • 1,436
  • 5
  • 19
  • 41