MERN Stack Deployment to Heroku Backend Not Working

Hello, I made an account here just to ask this question. I’ve been having trouble for three days now and I need to have this deployed for a project due on Tuesday. I’m very sure that I have some sort of silly mistake somewhere and I just don’t understand. I know a lot of my code may be messy because I’ve been desperately copying and pasting things in an attempt to come across a solution. If I can get any help, it would be much appreciated !

Below is my server.js code:

const express = require('express');
const cors = require('cors');
const mongoose = require('mongoose');
require('dotenv').config();
const app = express();
const port = process.env.PORT || 5000
console.log(port)
app.use( (req, response, next)=> {
  response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
response.setHeader("Access-Control-Allow-Headers", "Access-Control-Allow-Headers, Origin,Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");

  next();
});

app.use(cors())
app.use(express.json());

const uri = process.env.PORT;
console.log(uri)

const connection = "mongodb+srv://xxxx:xxxx@CLUSTERNAME.vtbxz.mongodb.net/xxxxxx?retryWrites=true&w=majority";
mongoose.connect(connection,{ useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false})
    .then(() => console.log("Database Connected Successfully"))
    .catch(err => console.log(err));

const classesRouter = require('./routes/classes');
const usersRouter = require('./routes/users');
const facultyRouter = require('./routes/faculty');
const sectionsRouter = require('./routes/section');
const adminRouter = require('./routes/admins');

app.use('/classes', classesRouter);
app.use('/users', usersRouter);
app.use('/faculty', facultyRouter);
app.use('/section', sectionsRouter);
app.use('/admins', adminRouter);



app.listen(process.env.PORT || 5000 , () => {
    console.log(`Server is running on port: ${port}`);
});

module.exports = app;

I changed the mongodb line to X’s in case, but in my code it’s all correct because I can login to my app locally. I have an .env with the following written:

ATLAS_URI=mongodb+srv://xxxx:xxxx@CLUSTERNAME.vtbxz.mongodb.net/xxxx?retryWrites=true&w=majority

Again I just used X’s instead of my password. Below is my package.json for the backend:

{
  "name": "backend",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node server.js",
    "heroku-postbuild": "cd client && npm install && npm run build"
    
        
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.21.1",
    "cors": "^2.8.5",
    "dotenv": "^8.2.0",
    "express": "^4.17.1",
    "mongoose": "^5.11.19",
    "react": "^17.0.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.7"
  }
}

And here is the package.json for the frontend:

{
  "name": "system-design",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@devexpress/dx-react-core": "^2.7.5",
    "@devexpress/dx-react-scheduler": "^2.7.5",
    "@devexpress/dx-react-scheduler-material-ui": "^2.7.5",
    "@material-ui/core": "^4.11.3",
    "@popperjs/core": "^2.7.0",
    "@syncfusion/ej2-react-schedule": "^18.4.46",
    "@testing-library/jest-dom": "^5.11.9",
    "@testing-library/react": "^11.2.5",
    "@testing-library/user-event": "^12.6.3",
    "@types/react-router-dom": "^5.1.7",
    "axios": "^0.21.1",
    "bootstrap": "^4.6.0",
    "dotenv": "^8.2.0",
    "node-schedule": "^2.0.0",
    "react": "^17.0.1",
    "react-big-calendar": "^0.33.0",
    "react-bootstrap": "^1.5.0",
    "react-dom": "^17.0.1",
    "react-native": "^0.64.0",
    "react-native-cli": "^2.0.1",
    "react-native-timetable": "^1.0.4",
    "react-router-dom": "^5.2.0",
    "react-scripts": "^4.0.3",
    "semantic-ui-css": "^2.4.1",
    "semantic-ui-react": "^2.0.3",
    "web-vitals": "^1.1.0"
  },
  "scripts": {
    "import": "mongo-import",
    "server": "nodemon server.js",
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ],
    "proxy": "http://localhost:5000"
  }
}

Im not sure if I need that proxy line, or if that is the cause of my error. I was just trying anything I could find online.

Below is my homepage.component.js. When deploying I know I should change the localhost part, but what do I change it to? When I tried only “/users/login” it did not work.

import React, { Component } from 'react';

import { Button, Icon } from 'semantic-ui-react';

import axios from 'axios';

export default class Navbar extends Component {

  constructor(props) {

    super(props);

    this.onChangeEmail = this.onChangeEmail.bind(this);

    this.onSubmit = this.onSubmit.bind(this);

    this.register=this.register.bind(this)

    this.faculty=this.faculty.bind(this)

    this.onChangePassword=this.onChangePassword.bind(this)

    this.state = {

      email: '',

      password:''

    }

  }

  

register(e){

window.location='/register'

}

faculty(e){

  window.location="/faculty"

}

  onChangeEmail(e) {

    this.setState({

      email: e.target.value

    })

  }

  onChangePassword(e) {

    this.setState({

      password: e.target.value

    })

  }

componentDidMount(){

  console.log(window.location.hostname)

}

  onSubmit(e) {

    e.preventDefault();

    const user = {

      email: this.state.email,

      password: this.state.password

    }

    console.log(user);

    axios.post('http://localhost:5000/users/login', user)

      .then(res =>{ 

        return JSON.stringify(res.data);

      }).then(data=>{

        console.log(data)

        window.location = `/student/${data}`

      });

    this.setState({

      email: '',

      password:''

      

    })

    

  }

render() {

    return (

        <div style = {{width:"100vh"}}>

        <form onSubmit={this.onSubmit}>

          <div className="form-group" style = {{width:"100vh",position: 'absolute', left: '50%', top: '30%',

        transform: 'translate(-50%, -50%)'}}> 

            <label>Email: </label>

            <input  type="text"

                required

                value={this.state.email}

                onChange={this.onChangeEmail}

                className="form-control"

               

                />

          </div>

          <div  style = {{width:"100vh",position: 'absolute', left: '50%', top: '50%',

        transform: 'translate(-50%, -50%)'}} className="form-group"> 

            <label>Password: </label>

            <input  input type="password" name="password"

                required

                value={this.state.password}

                onChange={this.onChangePassword}

                className="form-control"

                />

          </div>

          <div>

    <Button  animated  style = {{width:"10vh",position: 'absolute', left: '50%', top: '70%',

        transform: 'translate(-50%, -70%)'}} type="submit" value="login" >

      <Button.Content visible>Login</Button.Content>

      <Button.Content hidden>

        <Icon name='arrow right' />

      </Button.Content>

    </Button>

  <button onClick={this.register} type="button"  type="button"

    style = {{position: 'absolute', left: '38%',top:'67.3%'}} >

   Register 

 </button>

 <button onClick={this.faculty} type="button"  type="button"

    style = {{position: 'absolute', left: '58%',top:'67.3%'}} >

   Teacher Login

 </button>

  </div>

  

        </form>

      </div>

    )

  }

}

When I go to my deployed site and try to login, I get this error: /users/login:1 Failed to load resource: the server responded with a status of 404 (Not Found)

Im honestly not sure what to do. Again Im quite new to this. My teacher is not that great and he hasn’t taught us anything, so I’ve been trying my best. I’m sure it’s a silly mistake somewhere that I just don’t see. Any help would be great.

Welcome there,

This definitely should not be like this for production. The important bit of code would be where you have defined:

Do you not have your code in a GitHub repo (or similar) where we could look at all of it?

I know I should change the localhost part, so it should only be /users/login instead of http://localhost:5000/users/login in my homepage component, right?

As for this

What is the important bit of code ? I don’t have a normal github repo, I’ve been using Heroku’s and Im not sure if that is accessible.

We need to be able to see what usersRouter is doing.

No, I do not believe that is accessible. I hope is it not, anyway :sweat_smile:

This is my users.js route:

const router = require('express').Router();

const { useReducer } = require('react');

let user = require('../models/user.js');

let sections=require('../models/sections.js')

let faculty=require('../models/faculty.js')

const mongoose = require('mongoose');

var x = 700000001;

router.route('/add').post((req, res) => {

  

    const u = new user({

        name: req.body.name,

        address:req.body.address,

        email:req.body.email,

        birthday:req.body.birthday,

        id:x,

        status:req.body.status,

        password:req.body.password,

        });

 x = x+1;

  u .save()

    .then(() => res.json('User added!'))

    .catch(err => res.status(400).json('Error: ' + err)); 

    console.log(u)

});

router.route('/login').post(async(req,res)=>{

    user.findOne({email:req.body.email}).then(user=>{

        if(!user){

            res.status(404).send("user does not exist please try again")

        }else{

            const l= req.body.password;

            flag2 = l.localeCompare(user.password);

            if(flag2){

                return res.send("100")

            }else{

                console.log(user)

               return res.status(200).send(user.id+"")

            }

        }

    }).catch(err=>console.log(err));

})

router.route('/:id').get((req, res) => {

    var x=req.params.id

    

    console.log(x)

       user.findOne({id:x})

      .then(user => res.json(user))

      .catch(err => res.status(400).json('Error: ' + err));

  });

 router.route('/transcript/:id').get(async(req,res)=>{

     const u= await user.findOne({id:req.params.id})

     console.log(u.transcript)

res.json(u.transcript)

 })

module.exports = router;

Is there a problem with the routes? Maybe they need to be changed in order to deploy properly? I have no idea, my teacher didn’t show us anything and he expects it deployed by this Tuesday.

I am struggling to see anything amiss. So, my suggestion is to debug by splitting and testing as small a part of the app as you can:

  • Does this work as expected locally?
  • Can you use something like Postman to query the server?
  • Is this just specific to Heroku? Take a nice dig through the logs (even as you build), maybe share them here as well.

Hope you get to the bottom of this.

Yes, the app works locally. Yes I can use Postman. The problem only seems to be with Heroku. Every time I deploy on it, it works, and I can go to my website. I just can’t login.

@labouel Hi,
Did you place every thing that is in .env into the config vars section? The .env file does not work in Heroku.

Go to your application > Settings > Reveal config vars and add what is in your .env file there.

Add this to the key field

ATLAS_URI

Add this to the value field with the real information.

mongodb+srv://xxxx:xxxx@CLUSTERNAME.vtbxz.mongodb.net/xxxx?retryWrites=true&w=majority

It looks something like this:

add_env_vars

Yes I have done this already. ATLAS_URI and the correct value, and I still have this error unfortunately. I’m really not sure what the problem is and I will have to deploy this by Tuesday.

I believe Heroku uses

MONGOLAB_URI

instead of ATLAS_URI.

I made the switch and for a second , one of the pages got info from our database, but then stopped working.
Just to be clear, where ever there is a part like this :

  axios.post('http://localhost:5000/users/login', user)

I should be changing it to:

  axios.post('/users/login', user)

Correct? Or should I put the URL to our website there instead, as some people on another site suggested? So like this:

  axios.post('http://alpha-uni.herokuapp.com/users/login', user)

The errors I get when logging in is usually “xhr.js:177 POST React App 404 (Not Found)”

I don’t really know how to fix this.

Is there an issue with the courses? Perhaps they should be changed to send appropriately?

This should not be necessary, but did it work?

I am really confused why you would be able to get a response from Postman, and not your frontend. So, unfortunately, I am out of ideas.

Yeah. When I make it Localhost5000 everything works when I run the server locally. However when I change it to simply (/users/login) and try to deploy it, it always says NOT FOUND when I try to login.

Hey, im having the same issues, i’ve tried everything, wondering if you were able to figure it out in the end! thanks!

Did you have Procfile in your deployed folders?

Yeah I have the Procfile setup. but no communication with the server. Is it possible that I need a proxy middleware to get it working? I have tried adding the proxy but I’m not too familiar with them so might have to dive into some documentation to do it properly…
Is there a way to check on heroku if your server is definately running? This would at least narrow it down to being a route problem

This is the docs for troubleshooting of the server: Troubleshooting Node.js Deploys | Heroku Dev Center

and for the front(React) you need static.json and you refer to your server in that file example: GuestBook-client/static.json at master · Mohamed-Magdey/GuestBook-client · GitHub