I'm a beginner trying to build a full-stack application using Express for the server-side and reactjs for the frontend. Basically, I want to call an API, retrieve the JSON-format data, and use that data on the frontend side.
What happens is that, when developing locally, I run the server and frontend code individually (using concurrently), and I can fetch data from the API without any issue. But, ultimately I want to deploy this full-stack application to Vercel.
So, I build the file with
npm run build
and then test the production environment locally using
serve -s build
When I open the production env. link, it doesn't seem to fetch data from the API. I can't figure out why this seems to happen.
Details below:
code directory
pacakge.json
(main part for production)
{
...
"main": "server.js",
"scripts": {
"start": "node server.js",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000"
}
pacakge.json
(main part for development)
{
...
"main": "server.js",
"scripts": {
"server": "node server.js",
"frontend": "react-app-rewired start",
"start": "concurrently --kill-others \"npm run frontend\" \"npm run server\"",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000"
}
server.js
/set
is the relative endpoint that calls the actual API. I have changed the api address for security reasons, but as I said I confirmed that the API works properly on development environment.
const express = require('express');
const app = express();
const path = require('path');
var cors = require('cors')
const bodyParser = require('body-parser');
const fs = require('fs')
const https = require('https')
const axios = require('axios')
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
const port = process.env.PORT || 5000;
console.log("Inside server.js >>>")
app.use(bodyParser.json())
app.use(express.json())
app.use(cors({ origin: true, credentials: true }));
app.post('/set', (req, res) => {
const httpsAgent = new https.Agent({
ca: process.env.REACT_APP_CERT,
cert: process.env.REACT_APP_CERT,
key: process.env.REACT_APP_KEY,
});
try {
const instance = axios.create({
httpsAgent
});
const options = {
url: 'https://12.34.56.78/abcd',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
'Access-Control-Expose-Headers': '*',
},
data: { some: json data
},
};
instance(options)
.then(async (response) => {
res.json(response.data)
})
.catch(err => res.send(err));
} catch(err){
console.error("GG", err);
}
});
if(process.env.NODE_ENV==='production'){
app.get('/',(req,res)=>{
app.use(express.static(path.resolve(__dirname,'build')))
res.sendFile(path.resolve(__dirname,'build','index.html'));
})
}
app.listen(port, () => console.log(`app listening on port ${port}!`));
module.exports = app
Function for API call inside reactjs
async function req(postdata) {
const instance = axios.create({
});
const options = {
url: 'http://localhost:5000/set',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials':true,
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
},
data: postdata,
};
const data = instance(options)
.then(async (response) => {
return response.data
})
.catch((e) => {
console.log('Network Error', e);
});
return data;
}
Things I tried so far:
- I checked the Network response in the developer tools of the browser. The screenshots of what it looks like when the API succeeded Vs when API failed to fetch data is posted below. At first glance, we can see that the response header is not shown when the API failed to fetch data.
Network response when API fails to fetch data
Console log axios network error message
Network response when API works in the development environment
- While testing the production mode with
serve -s build
, I also tried to run the server manuallynode server.js
. In that case, the API was fetching data. Does this mean the express server is somehow not up and running in the production build? Although, the staticindex.html
file is being served properly when I open the production link which should mean the server as such is running right..?
Hope the above references are good enough to help me out! How should I go about solving it? Please help me out as it's driving me mad!
CodePudding user response:
I managed to find a solution for this. So, to get the API call working in production,
following are the two changes I made.
- In
server.js
Had to change the cors() part like this
app.use(cors({ origin: "*", credentials: true }));
- In the function for API call in reactjs
Had to remove the http://localhost:5000
and just make the request with relative endpoint /set
in my case.
const options = {
url: '/set',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials':true,
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,PATCH,OPTIONS',
},
data: postdata,
};
Pushed the changes to vercel and verified that API is able to fetch data!
Still, even after making these changes, I cannot imitate the production environment with serve -s build
(API call doesn't work)..