AngularDebutant
AngularDebutant

Reputation: 1576

Handling javascript errors in express

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?

Upvotes: 0

Views: 160

Answers (4)

AngularDebutant
AngularDebutant

Reputation: 1576

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));
  }

Upvotes: 0

Jack Yu
Jack Yu

Reputation: 2425

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.

Upvotes: 1

Jithin Zachariah
Jithin Zachariah

Reputation: 332

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

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

Upvotes: 0

JustRaman
JustRaman

Reputation: 1161

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

Upvotes: 1

Related Questions