I want to display suitable error messages based on the errors on the signup and login page from the backend. I was successful in fetching and displaying error messages for login but in the signup page, I am not able to get the 'User already exists' message to display on the screen but it is displaying on the console though. Just the email and password checks error messages are getting displayed in signup. Needed help on this that where i am going wrong. Below is the code
Backend:
const router = require("express").Router();
const {check,validationResult} = require("express-validator");
const bcrypt = require("bcrypt");
const JWT = require("jsonwebtoken");
const {users} = require("../database");
require("dotenv").config();
//sign up
router.post("/signup",
[
check("email","Invalid email").isEmail(),
check("password","Password must be atleadt 6 chars long").isLength({
min:6,
}),
],
async (req,res)=>{
const {email,password} = req.body;
//Validate user input
const errors = validationResult(req);
if(!errors.isEmpty()){
return res.status(400).json({
errors:errors.array(),
});
}
//Validate if user already exists
let user = users.find((user)=>{
return user.email === email;
});
if(user){
return res.status(200).json({
errors:[
{
email:user.email,
msg:"User already exists"
}
]
})
}
//Hashing password before saving to database
const salt = await bcrypt.genSalt(10);
console.log("salt:",salt);
const hashedPassword = await bcrypt.hash(password,salt);
console.log("hashed password:",hashedPassword);
users.push({
email,
password: hashedPassword,
});
//excluding sensitive info in JWT
const accessToken = await JWT.sign(
{email},
process.env.ACCESS_TOKEN_SECRET,
{
expiresIn: "2h",
}
);
res.json({
accessToken,
})
}
)
//Get all users
router.get('/users',(req,res)=>{
res.json(users);
})
//Login
router.post("/login",async(req,res)=>{
const {email,password} = req.body;
//Validate email
let user = users.find((user)=>{
return user.email === email;
});
if(!user){
return res.status(400).json({
errors: [{
msg:"Invalid credentials",
}
]
})
}
//Compare hashed password with the user password
let isMatch = await bcrypt.compare(password,user.password);
if(!isMatch){
return res.status(401).json({
errors:[
{
msg:"Email or password is invalid",
}
]
})
}
//Send JWT
const accessToken = await JWT.sign(
{email},
process.env.ACCESS_TOKEN_SECRET,
{
expiresIn:"2h"
}
)
res.json({
accessToken,
})
})
module.exports = router;
Frontend - authService.js:
import axios from "axios";
const API_URL = "http://localhost:3000/auth";
const signup = (email, password) => {
try{
return axios
.post(API_URL "/signup", {
email,
password,
})
.then((response) => {
//console.log(response.data.errors);
if (response.data.accessToken) {
localStorage.setItem("user", JSON.stringify(response.data));
}
console.log(response.data.errors?.map((error)=>console.log(error.msg)))
return response.data;
});
}
catch(error) {
return error;
}
};
const login = (email, password) => {
return axios
.post(API_URL "/login", {
email,
password,
})
.then((response) => {
if (response.data.accessToken) {
localStorage.setItem("user", JSON.stringify(response.data));
}
console.log(response.data.errors?.map((error)=>console.log(error.msg)))
return response.data;
});
};
const logout = () => {
localStorage.removeItem("user");
};
const getCurrentUser = () => {
return JSON.parse(localStorage.getItem("user"));
};
const authService = {
signup,
login,
logout,
getCurrentUser,
};
export default authService;
Frontend - Signup page:
import React, { useState } from "react";
import "./styles/Signup.css";
import { useNavigate } from "react-router-dom";
import authService from "../services/auth.service";
function Signup() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [phone, setPhone] = useState("");
const [name, setName] = useState("");
const[error,setError] = useState("")
const navigate = useNavigate();
const handleSignup = async (e) => {
e.preventDefault();
try {
await authService.signup(email, password).then(
(response) => {
// check for token and user already exists with 200
// console.log("Sign up successfully", response);
//navigate("/login");
//window.location.reload();
},
(error) => {
console.log(error.response.data.errors?.map((error)=>setError(error.msg)));
}
);
} catch (error) {
console.log(error);
}
};
return (
<div className="signupContainer">
<div className="row">
<div className="col-lg-7 px-5 pt-5">
<h3 className="font-weight-bold py-3 text-white">Sign up</h3>
<form onSubmit={handleSignup}>
{<h4 className="errorMsg">{error}</h4>}
<div className="form-row">
<div className="col-lg-7">
<input
type="text"
placeholder="Phone"
value={phone}
onChange={(e) => setPhone(e.target.value)}
/>
</div>
</div>
<div className="form-row">
<div className="col-lg-7">
<input
type="text"
placeholder="Full Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</div>
</div>
<div className="form-row">
<div className="col-lg-7">
<input
type="text"
placeholder="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
</div>
<div className="form-row">
<div className="col-lg-7">
<input
type="password"
placeholder="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
</div>
<div className="form-row">
<div className="col-lg-7">
<button type="submit" className="signupBtn">
Sign up
</button>
</div>
</div>
</form>
</div>
</div>
{/*<form onSubmit={handleSignup}>
<h3>Sign up</h3>
<input
type="text"
placeholder="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
placeholder="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Sign up</button>
</form>*/}
</div>
);
}
export default Signup;
Frontend - Login page:
import React, { useState } from "react";
import "./styles/Login.css";
import { useNavigate } from "react-router-dom";
import authService from "../services/auth.service";
function Login() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const[error,setError] = useState("")
const navigate = useNavigate();
const handleLogin = async (e) => {
e.preventDefault();
try {
await authService.login(email, password).then(
() => {
//navigate("/home");
//window.location.reload();
},
(error) => {
console.log(error.response.data.errors?.map((error)=>setError(error.msg)));
}
);
} catch (error) {
console.log(error);
}
};
return (
<div className="signupContainer">
<div className="row">
<div className="col-lg-7 px-5 pt-5">
<h3 className="font-weight-bold py-3 text-white">Login</h3>
<form onSubmit={handleLogin}>
{<h4 className="errorMsg">{error}</h4>}
<div className="form-row">
<div className="col-lg-7">
<input
type="text"
placeholder="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
</div>
</div>
<div className="form-row">
<div className="col-lg-7">
<input
type="password"
placeholder="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
</div>
<div className="form-row">
<div className="col-lg-7">
<button type="submit" className="signupBtn">
Login
</button>
</div>
</div>
{/*<form onSubmit={handleLogin}>
<h3>Login</h3>
{error && <p style={{ color: "red" }}>{error}</p>}
<input
type="text"
placeholder="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
placeholder="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<button type="submit">Log in</button>
</form>*/}
</form>
</div>
</div>
</div>
);
}
export default Login;
CodePudding user response:
Your frontend expects signup error responses to have !== 200
status code.
Try to respond with 400
status code when user already exists:
let user = users.find((user)=>{
return user.email === email;
});
if(user){
return res.status(400).json({
errors:[
{
email:user.email,
msg:"User already exists"
}
]
})
}