0

My app works locally but once deployed to Heroku, every page works except the home page where the json data is displayed instead of the UI. On this page, I am listing the posts from the db so the posts in the db are being displayed as json data.

I tried prepending post routes with '/post' to stop api returning html on '/' route but now I'm getting this problem. Whatever I change, it just keeps switching between these two issues - either json data is displayed or index.html is returned instead of data.

How can I fix this? Thanks!

The route for that specific page (this is the first route): <Route path="/posts/" exact component={Home} />

server.js

// imports
...

require("dotenv").config();

// import routes
const authRoutes = require("./routes/auth");
const userRoutes = require("./routes/user");
const postRoutes = require("./routes/posts");
// app
const app = express();

// connect db
const url = process.env.MONGODB_URI 
mongoose.connect(url, {
  useNewUrlParser: true,
  useCreateIndex: true,
  useUnifiedTopology: true,
  useFindAndModify: false,
});
mongoose.connection
  .once("open", function () {
    console.log("DB Connected!");
  })
  .on("error", function (error) {
    console.log("Error is: ", error);
  });

// middlewares
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", '*');
  res.header("Access-Control-Allow-Credentials", true);
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
  res.header("Access-Control-Allow-Headers", 'Origin,X-Requested-With,Content-Type,Accept,content-type,application/json');
  next();
});

//middleware 
...

 // routes middleware
//  app.use(express.static(path.join(__dirname, './client/build')))

if (process.env.NODE_ENV === "production") {
  app.use(express.static("client/build"));
}
app.use(authRoutes);
app.use(userRoutes);
app.use('/post', postRoutes);

app.get("/*", function (req, res) {
  res.sendFile(path.join(__dirname, "./client/build/index.html"));
});

const port = process.env.PORT || 80;

app.listen(port, () => {
  console.log(`Server is running on port ${port}`);
});

ListPosts.js

// imports
...

import { API } from "../config";

class ListPosts extends React.Component {
  state = {
    title: "",
    body: "",
    date: "",
    posts: [],
  };

  componentDidMount = () => {
    this.getPosts();
  };

  getPosts = () => {
    axios
      .get(`${API}/post/`)
      .then((response) => {
        const posts = response.data;
        this.setState({ posts });
      })
      .catch((error) => {
        console.log(error);
      });
  };

  displayPosts = (posts) => {
    if (!posts.length) return null;
     return posts.map((post, index) => (
    ...
    ));
  };

  render() {
    return <div>{this.displayPosts(this.state.posts)}</div>;
  }
}

export default ListPosts;

list route/controller

router.get("/", list);

exports.list = (req, res) => {
  const sort = { title: 1 };
  Post.find()
    .sort(sort)
    .then((posts) => res.json(posts))
    .catch((err) => res.status(400).json("Error: " + err));
};
SK1dev
  • 1,049
  • 1
  • 20
  • 52
  • That's because your ``. This will send a GET request ('/post') to your backend and you have an API endpoint `app.use('/post')`. As you're also serving your frontend from the same domain. So ..., you might want to change that frontend ROUTE to `/posts` or something different. – Rishabh Anand Nov 02 '20 at 09:44
  • Thanks, I have changed it but the issue is with this is that the api request on this page then returns `index.html` instead of json data which stops the `.map` from working because it's trying to map through a html doc. @RishabhAnand – SK1dev Nov 02 '20 at 09:52
  • Uhmm, please make sure you didn't change the backend endpoint. You're supposed to send a request to `${API}/post`, if you make it anything else, you will be returned with a html doc as per your server configuration `app.use('/post', postRoutes); app.use('/*', ...)`; – Rishabh Anand Nov 02 '20 at 10:04
  • Yes, I didn't change the backend endpoint at all. @RishabhAnand – SK1dev Nov 02 '20 at 10:11
  • `app.use('/post', postRoutes); if (process.env.NODE_ENV === 'production') { app.use(express.static(path.join(__dirname, "client/build"))); app.get("*", (_, res) => { res.sendFile(path.join(__dirname, "client/build", "index.html")); }); }` also, a small change, because I feel this is the recommended way of serving your react app. Please copy this exactly how it's written, you have to delete the line number 56-58 as per github (server.js `master branch`). What do you mean frontend is running on port 8001? You're serving it statically. – Rishabh Anand Nov 03 '20 at 07:46
  • Thanks for taking a look at my repository. I've made the changes you mentioned except I had to leave the `/` before `*` at `app.get('/*'` as none of the requests worked otherwise. It has fixed the problem, my request returns data now and is displaying it, thanks so much! I have another question about how it's returning html instead of data (https://stackoverflow.com/questions/64496815/get-request-returns-index-html-doc-instead-of-json-data) , if you put your comment there as an answer, I'll give you the 100 reputation bounty. @RishabhAnand – SK1dev Nov 04 '20 at 09:07

0 Answers0