Home > front end >  How to render errors from node.js in react using fetch
How to render errors from node.js in react using fetch

Time:11-20

My application has a login page that works fine when the user enters the correct login credentials but while test casing for eventual wrong entries of either usernames or passwords I've realized that my catch block isn't able to correctly format the error object from the backend thus nothing is being rendered to the frontend.

I've tried using res.send(401).json({"message":"Unauthorized"}); in the backend instead of res.sendStatus(401); but the former method doesn't trigger an error response and rather returns as a response in the fetch.

While using res.sendStatus(401);, although the error is triggered my catch block isn't able to render it's response.

The backend:

const User = require('../model/User');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');

const handleLogin = async (req,res) => {
    const user = req.body.user.toLowerCase();
    const pwd = req.body.pwd;

    if(!user || !pwd) return res.sendStatus(400);
    const foundUser = await User.findOne({username: user}).exec();
    
    if(!foundUser) return res.sendStatus(401);

    const match = await bcrypt.compare(pwd, foundUser.password);
    console.log(match);
    if(match){
        const roles = Object.values(foundUser.roles);
        const accessToken = jwt.sign(
            {"userInfo": {
                "username": foundUser.username,
                "roles": roles
            }},
            process.env.ACCESS_TOKEN,
            {expiresIn: "300s"}
        );
        const refreshToken = jwt.sign(
            {"username": foundUser.username},
            process.env.REFRESH_TOKEN,
            {expiresIn: "1d"}
        );
        
        foundUser.refreshToken = refreshToken;
        const result = await foundUser.save();
        if(!result) return res.status(500);
        
        res.cookie("jwt",refreshToken,{httpOnly: true, sameSite: "None", maxAge: 24*60*60*1000});  
        res.json({user, roles, accessToken});
    }
    else{
        res.sendStatus(401);
    }   
}

module.exports = {handleLogin};

The fetch:

        fetch(BASE_URL   "/login", {
                
            method: "POST",
            headers: {
                "Content-Type":"application/json"
            },
            body: JSON.stringify({user: username,pwd})
        })
        .then(res => res.json())
        .then(data => {
            setUser(data);
            console.log(data);
        })
        .then(() => {
            setSuccess(true);
            setTimeout(() => {
                navigate("/");
            }, 1000);
        })
        .catch((err)=>{
            console.log(err);
            if(err.status == "401"){
                setErrMsg("Wrong username or password.")
            }
            else{
                setErrMsg("Login failed, try again.")
            }
            errRef.current.focus();
        })

Once the error is triggered the console displays the following error SyntaxError: Unexpected token 'U', "Unauthorized" is not valid JSON and in addition to that the error is not rendered to the frontend.

How can I correctly format the response from the backend or handle the error response from the front end to be able to correctly render it to the view?

CodePudding user response:

Your first then assumes that the response has valid json. Instead it should check if the response status is ok and if not, throw an error that will be caught by the catch.

.then(res => {
        if (res.ok) {
            return res.json();
        }
        throw new Error(res.status);
    })
  • Related