After deploying my mern app to Heroku, the GET
request on the home page ('http://localhost:8000/post/')
is now returning index.html
instead of json data
from the request. I'm getting 200 status
code but the response is html
. However, it works fine locally.
All the other requests are working except this one.
Whenever I think I've fixed it, Heroku displays the json data instead of the UI on this same route. I'm assuming that these issues are related.
How can I solve this? Thanks!
route/controller - list posts
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));
};
server.js
require("dotenv").config();
// import routes
...
const app = express();
// connect db - first arg is url (specified in .env)
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
...
// app.use(express.static(path.join(__dirname, './client/build')))
app.use(authRoutes);
app.use(userRoutes);
app.use('/post', postRoutes);
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/build"));
}
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
class ListPosts extends React.Component {
state = {
title: '',
body: '',
date: '',
posts: []
}
componentDidMount = () => {
this.getPosts()
}
getPosts = () => {
axios.get(`${API}/post`)
.then((response) => {
const data = response.data
this.setState({posts: [data]})
console.log(data)
})
.catch((error) => {
console.log(error)
})
}
displayPosts = (posts) => {
if (!posts.length) return null;
posts.map((post, index) => (
<div key={index}>
...
</div>
))
}
render() {
return (
<div>
{this.displayPosts(this.state.posts)}
</div>
)
}
}
export default ListPosts
If your API returns JSON, or some other form of pure data, it becomes much more useful. The existing app can still consume that data, and present it appropriately. Now, though, other things can use the API to access the same data.
The json () method of the Request interface reads the request body and returns it as a promise that resolves with the result of parsing the body text as JSON. Note that despite the method being named json (), the result is not JSON but is instead the result of taking JSON as input and parsing it to produce a JavaScript object.
First, we will fetch the JSON data by using the fetch API. This will return a promise with our JSON data. Then we will append the data dynamically by creating HTML elements on the fly. We will then append our JSON data to those elements. Getting JSON data from an API and display it on a web page is a common thing you will do quite often.
To get the JSON data from the response, we execute the json() function. The json() function also returns a promise. This is why we just return it and chain another then function. In the second then function we get the actual JSON data as a parameter. This data looks just like the data in our JSON file.
Your request 'http://localhost:8000/'
matches two route handler
app.get("/*", function (req, res) {
res.sendFile(path.join(__dirname, "./client/build/index.html"));
});
router.get('/', (list))
Since your client build route is placed above the list route it will always return the index.html because precedence matters in express when defining routes.
A good practice and solution is to always differentiate your api routes from the static ones by appending /api
before all routes as below
app.use('api/auth', authRoutes);
app.use('api/post', postRoutes);
app.use('api/user', userRoutes);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With