Error : Cannot POST /api/users

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 :innocent:

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

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.