In this MERN project that I cloned from GitHub, I have a Registration Form for users but on submitting i am getting error. When I check the network tab on developers tool I get Cannot POST /api/users
I am submitting the code for registration below
this is the code for src/components/auth/Register.js
import React, { useEffect, useState, createRef } from "react";
import Navbar from "../home/Navbar";
import { Link } from "react-router-dom";
import { HeaderOne, FormComponent } from "../../StyledComponents/utility";
import RegisterComponent from "../../StyledComponents/auth/Register";
import { connect } from "react-redux";
import {
setRegisterLoginLoading,
register,
registerLoginLoading
} from "../../actions/authAction";
const Register = ( props ) => {
const {setRegisterLoginLoading, redirectToLogin, alert, register, registerLoginLoading} = props
// Refs
const nameRef = createRef();
const emailRef = createRef();
const usernameRef = createRef();
const passwordRef = createRef();
const confirmPasswordRef = createRef();
const passwordMainRef = createRef()
const submitBtn = createRef();
useEffect(() => {
if (registerLoginLoading === true) {
submitBtn.current.value = "Loading...";
submitBtn.current.style.opacity = "0.5";
} else {
submitBtn.current.value = "Register";
submitBtn.current.style.opacity = "1";
}
}, [registerLoginLoading]);
useEffect( () => {
if ( redirectToLogin && alert.length === 0 ) {
props.history.push("/login")
}
}, [redirectToLogin, alert, props.history])
const [user, setUser] = useState({
name: "",
email: "",
username: "",
password: "",
confirmPassword: "",
company: ""
});
const { name, email, username, password, confirmPassword, company } = user;
const [disableSubmit, setDisableSubmit] = useState(true);
const handleSubmit = e => {
setRegisterLoginLoading()
e.preventDefault();
if ( company ) {
register({
name,
email,
username,
password,
confirmPassword,
company
});
} else {
register( {
name,
email,
username,
password,
confirmPassword
});
}
}
const emailRegex = /^([a-z0-9\.\-_]+)@([a-z0-9\.\-_]+)\.([a-z]{2,6})$/i;
const whiteSpaceRegex = /\S/;
useEffect(() => {
if (
whiteSpaceRegex.test(name) &&
name.length >= 5 &&
emailRegex.test(email) &&
whiteSpaceRegex.test(username) &&
username.length >= 4 &&
password === confirmPassword &&
password.length >= 5
) {
setDisableSubmit(false);
} else {
setDisableSubmit(true);
}
}, [disableSubmit, user]);
const onChange = e => {
const updatedUser = {
...user,
[e.target.name]: e.target.value
};
setUser( updatedUser );
handleErrorMessage(e)
};
const disabledBtn = () => {
if (disableSubmit)
return {
color: "rgba(0, 0, 0, 0.26)",
boxShadow: "none",
backgroundColor: "rgba(0, 0, 0, 0.12)",
cursor: "default",
pointerEvents: "none"
};
};
const errorMessageStyle = {
color: "red",
display: "none"
};
const handleErrorMessage = e => {
switch (e.target.name) {
case "name":
if (!whiteSpaceRegex.test(e.target.value) || e.target.value.length < 5) {
nameRef.current.style.display = "block";
} else {
nameRef.current.style.display = "none";
}
break;
case "email":
if (!emailRegex.test(e.target.value)) {
emailRef.current.style.display = "block";
} else {
emailRef.current.style.display = "none";
}
break;
case "username":
if (!whiteSpaceRegex.test(e.target.value) || e.target.value.length < 4) {
usernameRef.current.style.display = "block";
} else {
usernameRef.current.style.display = "none";
}
break;
case "password":
if (e.target.value.length < 5) {
passwordRef.current.style.display = "block";
} else {
passwordRef.current.style.display = "none";
}
break;
case "confirmPassword":
if (passwordMainRef.current.value !== e.target.value) {
confirmPasswordRef.current.style.display = "block";
} else {
confirmPasswordRef.current.style.display = "none";
}
break;
default:
break;
}
};
return (
<>
<Navbar public />
<RegisterComponent>
<div>
{alert.map(elem => (
<p
style={{
maxWidth: "320px",
margin: "1rem auto 0 auto",
borderRadius: "10px",
padding: ".5rem",
textAlign: "center",
color: "white",
background: elem.type === "success" ? "green" : "red"
}}
key={elem.id}
>
{elem.msg}
</p>
))}
</div>
<HeaderOne>Create an account</HeaderOne>
<p className="helper-form-text">
Already have an account? <Link to="/login">Log In</Link>
</p>
<FormComponent onSubmit={handleSubmit} registerLoginForm>
<div className="form-group">
<input
type="text"
name="name"
id="name"
required
placeholder="Name"
minLength="5"
value={name}
onChange={onChange}
/>
<small ref={nameRef} style={errorMessageStyle}>
Name must be at least 5 characters long
</small>
</div>
<div className="form-group">
<input
type="email"
name="email"
id="email"
placeholder="Email"
required
value={email}
onChange={onChange}
/>
<small ref={emailRef} style={errorMessageStyle}>
Email should be valid one
</small>
</div>
<div className="form-group">
<input
type="text"
name="username"
id="username"
placeholder="Username"
required
minLength="4"
value={username}
onChange={onChange}
/>
<small ref={usernameRef} style={errorMessageStyle}>
Username must be at least 4 characters long
</small>
</div>
<div className="form-group">
<input
type="text"
name="company"
id="company"
placeholder="Your company"
value={company}
onChange={onChange}
/>
</div>
<div className="form-group">
<input
type="password"
name="password"
id="password"
required
placeholder="Choose a strong password"
value={password}
onChange={onChange}
minLength="5"
ref={passwordMainRef}
/>
<small ref={passwordRef} style={errorMessageStyle}>
Password must be at least 5 characters long
</small>
</div>
<div className="form-group">
<input
type="password"
name="confirmPassword"
id="confirmPassword"
required
placeholder="Confirm your password"
value={confirmPassword}
onChange={onChange}
minLength="5"
/>
<small ref={confirmPasswordRef} style={errorMessageStyle}>
Passwords don't match
</small>
</div>
<input
style={disabledBtn()}
type="submit"
value="Register"
ref={submitBtn}
className="submit-btn"
/>
</FormComponent>
</RegisterComponent>
</>
);
};
const mapStateToProps = state => ({
registerLoginLoading: state.auth.registerLoginLoading,
alert: state.auth.alert,
redirectToLogin: state.auth.redirectToLogin
});
const mapDispatchToProps = {
register,
setRegisterLoginLoading
};
export default connect(mapStateToProps, mapDispatchToProps)(Register);
this is the code for src/actions/authAction.js
import {
AUTH_ERROR,
REGISTER_SUCCESS,
REGISTER_FAIL,
SET_AUTH_ALERT,
REMOVE_AUTH_ALERT,
CLEAR_ERRORS,
LOGIN_FAIL,
LOGIN_SUCCESS,
USER_LOADED,
LOGOUT,
SET_REGISTER_LOGIN_LOADING,
CLEAR_ALERT,
CLEAR_REDIRECT_TO_LOGIN
} from "./types";
import callAxios from "../utils/callAxios";
import setAuthToken from "../utils/setAuthToken";
import uuid from "uuid";
export const loadUser = () => async dispatch => {
if (localStorage.getItem("inventoryAppToken")) {
setAuthToken(localStorage.getItem("inventoryAppToken"));
}
try {
const res = await callAxios("GET", "/auth");
dispatch({
type: USER_LOADED,
payload: res.data.user
});
} catch (err) {
dispatch({
type: AUTH_ERROR,
payload: err.response
});
}
};
export const login = data => async dispatch => {
const id = uuid.v4();
try {
const res = await callAxios("POST", "/auth", data);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data,
alert: {
msg: "Logged in successfully. Redirecting you to your dashboard.",
type: "success",
id
}
});
} catch (err) {
dispatch({
type: LOGIN_FAIL,
payload: err.response.status,
alert:
err.response.status === 400
? {
msg: "Incorrect username or password",
type: "failure",
id
}
: {
msg: "Something went wrong. please refresh the page.",
type: "failure",
id
}
});
} finally {
setTimeout(() => {
dispatch({
type: CLEAR_ALERT,
payload: id
});
}, 3000);
}
};
export const register = ( data ) => async dispatch => {
const id = uuid.v4()
try {
const res = await callAxios("POST", "/users", data);
dispatch({
type: REGISTER_SUCCESS,
payload: res.data,
alert: {
msg: "Signed up successfully. Redirecting you to login.",
type: "success",
id
}
});
} catch (err) {
dispatch({
type: REGISTER_FAIL,
payload: err.response,
alert:
err.response.status === 400
? {
msg: err.response.data.msg,
type: "failure",
id
}
: {
msg: "Something went wrong. please refresh the page.",
type: "failure",
id
}
});
} finally {
setTimeout(() => {
dispatch({
type: CLEAR_ALERT,
payload: id
});
}, 3000);
}
}
export const setRegisterLoginLoading = () => {
return {
type: SET_REGISTER_LOGIN_LOADING
};
};
export const clearErrors = () => {
return {
type: CLEAR_ERRORS
};
};
export const clearRedirectToLogin = () => {
return {
type: CLEAR_REDIRECT_TO_LOGIN
}
}
export const logout = () => {
return {
type: LOGOUT
};
};
this is the code for routes
const express = require("express");
const router = express.Router();
const User = require("../models/User");
const { check, validationResult } = require("express-validator");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const config = require("config");
const authenticator = require("../middleware/authenticator");
// Route --------- POST api/users
// Description --- Register users
// Access -------- Public
router.post(
"/",
[
// validate client response via express-validator
check("name")
.isLength({ min: 5 })
.withMessage("Your name must be at least 5 characters long"),
check("email")
.isEmail()
.withMessage("Please include a valid email address"),
check("username")
.isLength({ min: 4 })
.withMessage("Your username must be at least 4 characters long"),
check("password", "Your password must be at least 5 characters long")
.not()
.isIn(["password", 123, "god"])
.withMessage("Do not use a common word as your password")
.isLength({ min: 5 })
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).json({ errors: errors.array() });
}
const { name, email, username, password, company } = req.body;
try {
let user = await User.findOne({ email });
let findUsername = await User.findOne({ username });
// Check that no two users are created that have the same email and usernames
if (user && findUsername) {
return res.status(400).json({
msg: "User already exists!. Choose another email and username"
});
}
if (user) {
return res.status(400).json({
msg: "User already exists!. Choose another email"
});
}
if (findUsername) {
return res
.status(400)
.json({ msg: "User already exists!. Choose another username" });
}
// const memberSince = await date.slice( 0, 10 ).split( "-" ).join( "/" );
// const shit = await User.findOne({email: "johndoe@gmail.com"})
// console.log( shit.date )
// return
user = new User({
name,
email,
username,
password,
company
});
// hash password with bcrypt
const salt = await bcrypt.genSalt(10);
// The above asynchronously creates a salt
user.password = await bcrypt.hash(password, salt);
// The above asynchronously generates a hashed version of the string password
// save user to database
await user.save();
// create jsonwebtoken
const payload = {
user: {
id: user.id
}
};
// sign the payload
jwt.sign(
payload,
config.get("jwtSecret"),
{
expiresIn: 360000
},
(err, token) => {
if (err) throw err;
res.json({ token, msg: "User successfully created!" });
}
);
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
}
);
// Edit a user's details
router.put(
"/:userId",
[
authenticator,
[
check("email", "Please include a valid email address")
.optional({ checkFalsy: true })
.isEmail(),
check("password", "Your password must be at least 5 characters long")
.optional({ checkFalsy: true })
.isLength({ min: 5 }),
check("username", "Your username must be more than four characters.")
.optional({ checkFalsy: true })
.isLength({ min: 4 })
.isLength({ min: 5 }),
check("name", "Your name must be at least five characters.")
.optional({ checkFalsy: true })
.isLength({ min: 4 })
.isLength({ min: 5 }),
check("company", "You company name must be at least 4 characters")
.optional({ checkFalsy: true })
.isLength({ min: 4 })
]
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(401).json({ errors: errors.array() });
}
try {
let user = await User.findById(req.params.userId);
if (!user) {
return res.status(404).json({ msg: "User does not exist!!" });
}
if (user._id.toString() !== req.user.id) {
return res.status(401).json({ msg: "Not authorized" });
}
const { name, email, password, username, company } = req.body;
// check if email or username is already taken
const checkUsername = await User.findOne({username})
const checkEmail = await User.findOne({email})
if ( checkUsername && checkEmail ) {
return res.status(400).json({msg: "Username and Email are already taken"})
}
if ( checkUsername ) {
return res.status( 400 ).json( { msg: "Username is already taken" } )
}
if ( checkEmail) {
return res.status(400).json({msg: "Email is already taken"})
}
let userField = {};
if (name) {
userField.name = name;
}
if (email) {
userField.email = email;
}
if (password) {
// hash password and save
const salt = await bcrypt.genSalt(10);
userField.password = await bcrypt.hash(password, salt);
}
if (username) {
userField.username = username;
}
if (company) {
userField.company = company;
}
user = await User.findByIdAndUpdate(
req.params.userId,
{ $set: userField },
{ new: true }
);
// create new jsonwebtoken
const payload = {
user: {
id: user.id
}
};
jwt.sign(
payload,
config.get("jwtSecret"),
{ expiresIn: 36000 },
(err, token) => {
if (err) throw err;
res.json({ msg: "Successfully updated!", token });
}
);
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
}
);
// Route -------- DELETE /api/auth
// access ------- Private
// Desc -------- Delete a user's account
router.delete("/", authenticator, async (req, res) => {
try {
let user = await User.findById(req.user.id);
if (!user) {
return res.status(404).json({ msg: "User does not exist!!" });
}
if (user._id.toString() !== req.user.id) {
return res.status(401).json({ msg: "Not authorized" });
}
user = await User.findByIdAndDelete(req.user.id);
res.json({ msg: "Account successfully deleted" });
} catch (err) {
console.error(err.message);
res.status(500).send("Server Error");
}
});
// Later, make it possible to delete a user and edit one's details
// Update,👆 done 😁
module.exports = router;
You can try the entire project in your local machine. The github link of the entire project is given here https://github.com/Eronmmer/inventory-app.git