Send only JSON error instead of html in node.js

Issue

Whenever a user registers in the app with invalid details like phone-number or email I want to throw an error as JSON object but it is displaying the html in the postman response.

The register route:

exports.register = async (req, res) => {
  try {
    var isValidated = await userService.validateInDatabase(req);
    if (!isValidated)
      return res
        .status(409)
        .json({ error: "Phone number or email is already registered" });

    var user = await userService.create(req.body);
    var token = await sendVerification(user);
    return res.status(201).json({ user, token });
  } catch (e) {
    return res.status(400).json({ message: e.message });
  }
};

The validate function:

const validate = (schema) => (req, res, next) => {
  const validSchema = pick(schema, ["params", "query", "body"]);
  const object = pick(req, Object.keys(validSchema));
  const { value, error } = Joi.compile(validSchema)
    .prefs({ errors: { label: "key" }, abortEarly: false })
    .validate(object);

  if (error) {
    const errorMessage = error.details
      .map((details) => details.message)
      .join(", ");
    return next(new ApiError(httpStatus.BAD_REQUEST, errorMessage));
  }
  Object.assign(req, value);
  return next();
};

The API endpoint for user registration:

router
  .route("/register")
  .post(validate(userValidation.createUser), User.register);

The error:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <title>Error</title>
</head>

<body>
    <pre>Error: &quot;phoneNumber&quot; length must be at least 10 characters long...</pre>
</body>

</html>

The apiError function:

class ApiError extends Error {
  constructor(statusCode, message, isOperational = true, stack = "") {
    super(message);
    this.statusCode = statusCode;
    this.isOperational = isOperational;
    if (stack) {
      this.stack = stack;
    } else {
      Error.captureStackTrace(this, this.constructor);
    }
  }
}

Solution

By passing an error to the next callback, it gets passed to Express’s error handling middleware, which in turn will render an HTML error page.

If you want to return validation errors as JSON, return a response directly from validate instead:

// not this:
return next(new ApiError(httpStatus.BAD_REQUEST, errorMessage));

// but this:
return res.status(400).json({ message: errorMessage });

Alternatively, if you want to streamline error handling in your app overall, you can use a custom error handling middleware which could, for instance, always return a JSON response in case an ApiError was thrown:

app.use((err, req, res, next) => {
  if (err instanceof ApiError) {
    return res.status(err.statusCode).json({ message: err.message }) 
  }
  // pass the error to the default error handler
  return next(err);
});

Answered By – robertklep

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published