skip to Main Content

When my login function encounters an error, such as when the email or password is missing, or when the student does not exist or their email is not verified, the response from the server is in HTML format instead of JSON. This HTML response includes an error message along with a stack trace, which is not suitable for consumption by frontend applications expecting JSON responses.

const asyncHandler = (requestHandler) => {
    return (req,res,next) => {
        Promise.resolve(requestHandler(req,res,next)). 
        catch((err)=>next(err))
    }
}

export {asyncHandler}

the ApiError class to throw custom error messages

class ApiError extends Error{
    constructor(
        statusCode,
        message = "Something went wrong",
        errors = [],
        stack = ""
    ){
        super(message)
        this.statusCode = statusCode
        this.data = null,
        this.message = message 
        this.success = false
        this.errors = errors

        if(stack){
            this.stack = stack
        }
        else{
            Error.captureStackTrace(this,this.constructor)
        }

    }
}

export {ApiError}

login function, it works fine but not when in error handling

const login = asyncHandler(async(req,res) => {

    const {Email, Password} = req.body;

    /*if(!Email){
        throw new ApiError(400,"E-mail is required")
    }
    if(!Password){
        throw new ApiError(400,"Password is required")
    }*/

    const result = await authSchema.validateAsync(req.body)

    const StdLogin = await student.findOne({
        Email
    })

    if(!StdLogin){
        throw new ApiError(400, "Student does not exist")
    }

    if(!StdLogin.Isverified){
        throw new ApiError(401, "Email is not verified");
    }

    const StdPassCheck = await StdLogin.isPasswordCorrect(Password)

    if(!StdPassCheck){
        return res.status(400).json({ error: "Password is incorrect" });
    }

    const tempStd = StdLogin._id

    
    const {Accesstoken, Refreshtoken} =  await generateAccessAndRefreshTokens(tempStd)

    const loggedInStd = await student.findById(tempStd).select(-Password -Refreshtoken)

    const options = {
        httpOnly:true,
        secure:true,
    }

    return res
    .status(200)
    .cookie("Accesstoken", Accesstoken, options)
    .cookie("Refreshtoken", Refreshtoken, options)
    .json(
        new ApiResponse(
            200,{
            user:loggedInStd
            }, "logged in"
            )
    )

})

RESPONSE I AM GETTING INCASE OF ERROR:

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

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

<body>
    <pre>Error: Student does not exist<br> &nbsp; &nbsp;at file:///C:/parag/CollegeProject/e-Learning-Platform/backend/src/controllers/student.controller.js:133:15<br> &nbsp; &nbsp;at process.processTicksAndRejections (node:internal/process/task_queues:95:5)</pre>
</body>

</html>

I want the function to return error or json data incase of error

2

Answers


  1. await throws?

    If either const result = await authSchema.validateAsync... or await student.findOne... throws, the inline handler function throws and hence rejects its returned promise, which causes

    Promise.resolve(requestHandler(req,res,next))
    

    in asyncHandler to reject which is caught and handled in asyncHandler by calling next(err). In express at least, next(err) invokes an in-built error handler that responds to the request with an HTML page formatted as described in the post.

    The issue is consistent with next(err) being called, which is consistent with one of the await statements throwing without being caught (before the APIError Error extension is even used in runtime code).

    TL;DR

    Solutions could be to add try/catch statements around await statements that are capable of throwing and explicitly handle errors in a controlled manner, or by using APIError to create a consumable response instead of calling next(err) within asyncHandler.

    Disclaimer: this answer has not reviewed the design or use of APIError in any way.

    Login or Signup to reply.
  2. When your app throw an Error, if you don’t have any middleware to handle and return a json following res object, nodejs will return a html.
    enter image description here

    You need a middleware like this:

    const returnError = (err, req, res, next) => {
      const statusCode = err.statusCode || 500;
      let error;
      if (err instanceof ApiError) {
        error = {};
        error.data = err.data;
        error.statusCode = err.statusCode;
        error.message = err.message;
        error.errors = err.errors;
        error.success = err.success;
      } 
      return res.status(statusCode).json({
        success: error.success !== undefined ? error.success : false,
        status: statusCode,
        message: error.message || 'Internal server error',
        errors: error.errors || [],
        data: error.data
      });
    };
    

    In app.js or index.js

    app.use(returnError);
    

    The result:
    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search