Home > Blockchain >  GET request returning html not object, route returning cannot get in Heroku server
GET request returning html not object, route returning cannot get in Heroku server

Time:12-24

I have a react app, using Postman for testing, to get HTTP requests runing on a Heroku server with client and server in a single root folder.

After deployment, I have run into a problem with the react-router on the Heroku server, where I get a CANNOT Get error after refreshing a page or manually entering the endpoint. To solve this error I added a wild card endpoint to redirect the route back to index.html in server.js (code below).

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

Once the above error was fixed I have run into another problem. I am now unable to get the JSON data via the GET request, and instead in Postman html.index is returned. To solve this problem I removed the code above, however, this solution revolves back to the first error and I am stuck in a circular loop, of fixing the first error and dealing with the second error.

I believe I can write an if statement that checks the route to redirect to index.html only when needed and this is what I have tried below, but it doesn't work and I am not sure how to write out the if statement to fix these two revolving errors.

app.get("*", (req, res) => {
  let url = path.join(__dirname, '../client/build', 'index.html');
  if (!url.startsWith('/app/')) // <-- not sure what to replace here to make code work
    url = url.substring(1);
  res.sendFile(url);
});

How can I fix these two errors with an if statement or another solution dealing with react-router and the Heroku server?

my code server.js

const mongoose = require("mongoose");
const path = require("path");
const express = require("express");
const app = express();
const cors = require("cors");
const logger = require("morgan");
const PORT = process.env.PORT || 3001;

require("./models/CalanderData"); 
const router = require("./routes/routes");

app.get("/api", (req, res) => {
  res.json({ message: "Hello from server!" });
});

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

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cors());
app.use(logger("dev"));

app.get("*", (req, res) => {
  let url = path.join(__dirname, '../client/build', 'index.html');
  if (!url.startsWith('/app/')) // <-- not sure what to replace here to make code work
    url = url.substring(1);
  res.sendFile(url);
});

//MonogoDB code to access DB

app.use("/", router);

app.listen(PORT, () => {
  console.log(`Express running PORT ${PORT}`);
});

routes.js

const express = require("express");
const router = express.Router();
const calDataController = require("../controllers/CalDataController");  

router.get('/get', calDataController.getData);   
// I have other routes but /get is the one I am testing 

module.exports = router;

CodePudding user response:

There's a handy piece of information in the Create React App documentation around deployment and client-side routing.

Your Express app should have the following

app.use(logger("dev"));
app.use(cors()); // always register CORS before other request handling middleware
app.use(express.json()); // you only need this once
app.use(express.urlencoded()); // do you even need this?

// Register API routes
app.get("/api", (req, res) => {
  res.json({ message: "Hello from server!" });
});

app.use("/", router);

// Register client routes / middleware
const CLIENT_BUILD_DIR = path.join(__dirname, "../client/build");

app.use(express.static(CLIENT_BUILD_DIR));

app.get("/*", (req, res) => {
  res.sendFile(path.join(CLIENT_BUILD_DIR, "index.html"));
});

The main thing to note is that that catch-all route is defined as /* and is registered last. This is so it does not conflict with other routes.

CodePudding user response:

I am posting my solution which is Phils above however, I am using controllers because I don't want to have a bunch of routes on my app.js on the server side, so with that, I need to have the Database code BEFORE the app.use("/", router); or the app breaks.

As far as the order Phil is correct, and that coupled with keeping the MongoDB code before the route request worked :)

const mongoose = require("mongoose");
const path = require("path");
const express = require("express");
const app = express();
const cors = require("cors");
const logger = require("morgan");
const PORT = process.env.PORT || 3001;

require("./models/CalanderData"); 
const router = require("./routes/routes");

app.use(logger("dev"));
app.use(cors()); // always register CORS before other request handling middleware
app.use(express.json()); // you only need this once

//MONGO DB CODE 

// Register API routes
app.get("/api", (req, res) => {
  res.json({ message: "Hello from server!" });
});

// Register client routes and middleware
const CLIENT_BUILD_DIR = path.join(__dirname, '../client/build')

app.use(express.static(CLIENT_BUILD_DIR));

//notice the order here 
app.use("/", router);

app.get("/*", (req, res) => {
  res.sendFile(path.join(CLIENT_BUILD_DIR, "index.html"));
});

app.listen(PORT, () => {
  console.log(`Express running PORT ${PORT}`);
});
  • Related