Configuring a React-Express App on Heroku to Pull Data in an Ajax Request - reactjs

I have a React-Express app that pulls data from a MongoDB database on mLab.
On my server.js file, I have the api port set as such:
var port = process.env.PORT || 3001;
And it listens as such:
app.listen(port, function() {
console.log(`api running on port ${port}`);
});
Currently, in my React app, one of the components makes an AJAX call to the database on mLab using the url of "http://localhost:3001/api/data", which works fine and pulls the data I requested.
However, when I deploy the app to Heroku, I'm not sure how to configure the server.js and the url in the React app, so the React app is able to pull the data from the database.
I've conferred with mLab, and there are no issues, and I've conferred with Heroku, and this is beyond the scope of their support.
UPDATE: Is it that the process.env.PORT variable needs to be set or redirected?
Any ideas what I need to do?
Thanks!

If your express app is serving both your bundled react app and your api, you need to make sure that express knows that the /api endpoint needs to be NOT served to the react app.
Not sure what your server code looks like, but this has worked for me:
if (process.env.NODE_ENV === 'production') {
app.get(/^\/(?!api).*/, (req, res) => { // don't serve react app to api routes
res.sendFile(PATHTOREACTBUNDLE));
});
};
Basically, you want to tell express that, if in production mode (deploy on heroku), serve all endpoints, except the api endpoint (/^/(?!api) to your react bundle.

Related

How to change localhost API URL when deployed to Heroku?

I've deployed an server-side rendering React app (bundled without CRA):
it has an express server for server-side rendering (listens to port 3000 or process.env.PORT)
it has an express server for the API that serves the frontend (listens to port 8080 or process.env.PORT)
On localhost, the frontend makes a request to http://localhost:8080/api to get the data, which works perfectly.
From my understanding, when the app is in production, the base API URL should be the app's URL (eg. https://myapp.herokuapp.com) instead of http://localhost:8080, so I added this change in my code:
if the app is in dev, the frontend calls http://localhost:8080/api
if the app is in prod, the frontend calls https://myapp.herokuapp.com/api(I added https://myapp.herokuapp.com/as a config var in Heroku)
However, it doesn't work. My app is deployed successfully to Heroku and the SSR renders correctly, but the API call fails. (I also tried https://myapp.herokuapp.com/api:3000 which fails)
What should be the API URL to call a local server when the app is in production?
thanks a lot!
Well, as far as I know Heroku doesn't allow multiple ports and you will not be able to open 3000 for web and 8080 for api.
You can serve both on the same port and route /api to the api.
I have worked on a project that uses similar approach and below is the code:
app.use('/api', router); // every api route is in the router
app.use(express.static(staticDir));
It is also deployed to heroku.
full repo if you wish to take a look - https://github.com/berkeli/breteau-dashboard/blob/main/server/utils/createServer.js

locally host firebase backend with react frontend together, for debugging

I am building a react website with firebase functions backend.
I'm using firebase serve to locally host the node.js backend that I connect to my react code through express API endpoints, and I am using react-scripts start to test my react frontend app.
all my get requests in my react app use /some endpoint to communicate with my firebase localserver. But they are running on different ports. firebase serves it on localhost:5000 while react live server hosts it at localhost:3000.
I tried many things and couldn't get any useful way to make this work. I at last added my react project as a subfolder in my firebase project and made the hosting public path at firebase.json to my react build directory. It works now but I always have to run npm run build on my react app on every change, to make it compile my app into the build directory, which is painfully slow.
What is the proper way to do this? debug react app and firebase backend together.
I finally enabled cross-origin-requests on my server using cors module
Serverside code
const cors = require("cors");
app.get("/test", (req, res) => {
return cors()(req, res, async () => {
res.send("working...");
});
});
Serverside code
And then adding a simple config file in the react side, to switch between debugging and deployed testing really helped.
config.js
var domain = "";
// domain = "http://localhost:5000";
export {domain}
then whenever I use apis in react, I simply comment/uncomment the second line to switch between local and deployed testing.
Then whenever I use APIs, I append `domain` before every url in all references, eg fetch requests
import { domain } from "config.js";
fetch(domain + "/int-search", ...
Then it worked fine running both the firebase backend and the react application on localhost, using firebase serve and npm start for my react app.

How to deploy chat server on heroku

So I've just created simple chat app with React, NodeJS, Express.JS and SocketIO. I'm going to deploy it on Heroku.
The problem is I'm not sure could I run both frontend and backend on the same URL. When I first created this chat locally, I've run front-end on localhost:3000 (default by Create-React-App) and backend on localhost:8000.
For the front-end side, I did it like this in external API.js file:
import io from 'socket.io-client';
let socket;
export const api = {
open: () => {
socket = io('http://localhost:8000');
}
}
For the backend side, I did it like this:
let express = require('express');
let io = require('socket.io')(8000);
So, you see, they're both on different ports. On my computer, it works perfectly. I'm not sure they could work locally on the same port (if I'm trying to switch 8000 port on back-end side to port 3000 it unfortunately doesn't work correctly - front and backend can't work on the same port, HTTP 404 error occurs).
My question is: is there any reason/is it even possible to put it on the same port? Because here's the problem number 2:
I've tried to deploy it on heroku, for the front-end side I've used Heroku Buildpack for create-react-app and it works fine, but totally don't know how to use it to deploy server-side. Should I create separate heroku address for the backend? And, at the code above, change paths like:
let socket;
export const api = {
open: () => {
socket = io('http://myherokuaddress');
}
}
and
let express = require('express');
let io = require('socket.io')(http://myherokuaddress);
?
In heroku you can't define port manually. use this code instead of port 8000.
process.env.PORT
You can do what Zenith said, however, the best practice is to use different servers for frontend and backend code, that way you can build mode frontend apps that uses the same backend code. And, if for some reason, your frontend server is down, you will only need to host the frontend code anywhere else and still using the same backend.

After deploying React/Express app to Heroku unable to start passport.js flow (page reloads instead) [duplicate]

I'm building a node + express server, with create-react-app to the frontend.
I used passportjs for auth routes handling, and all the stuff totally working on localhost ( backend on port 5000 and frontend on port 3000, with a proxy ).
When I deploy to Heroku, seems like the server can't recognize my auth routes and so heroku serve up static index.html.
If I test my APIs with Postman all seems to work ( I can see the html page for google oauth ), but with an anchor tag in my react app or manually writing the endpoint in the url, I can see only the same page reloading.
My server index.js:
const express = require('express')
const passport = require('passport')
const mongoose = require('mongoose')
const path = require('path')
// KEYS
const keys = require('./config/keys')
// MONGOOSE MODELS
require('./models/User')
mongoose.connect(keys.mongoURI)
// PASSPORT SETUP
require('./config/passport')
// CREATE THE SERVER
const app = express()
// EXTERNAL MIDDLEWARES
require('./middlewares/external')(app)
// ROUTE HANDLERS
require('./routes/authRoutes')(app)
// PRODUCTION SETUP
if (process.env.NODE_ENV === 'production') {
// express serve up production assets ( main.js, main.css )
app.use(express.static('client/build'))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
// START THE SERVER
const PORT = process.env.PORT || 5000
app.listen(PORT)
Flow:
LOCALHOST:
react app starts -> I click 'Google Login' -> GET request to "/auth/google" -> google oauth flow -> redirect to "/" and my react app reappears, the user is logged in.
HEROKU:
react app on my-app.herokuapp.com/ -> click on "Google Login" -> the page reloads, nothing happens. the user is not logged in.
Please guys, help me.
Thanks
This is a result of the service worker being installed by default to make your app a Progressive Web App
To determine if this is an issue for you, test your heroku production mode app in incognito mode. The request for /auth/google should now reach the server and behave as it does in development.
Once you determine it is an issue, you can remove the
import registerServiceWorker from "./registerServiceWorker";
from your /client/src/index.js file.
You browser cache may already contain an installed service worker so you may have to
clear browser cache on a user browsers
uninstall the server worker programmatically
import { unregister } from './registerServiceWorker';
....
unregister();
I had the same issues with same symptoms exactly.
For me the cause was a typo in the keys: in server/config/prod.js I had a line reading cookieKey: process.env.COOKIE_KEY but in Heroku Config Variables that variable was named cookieKey. Renaming it to COOKIE_KEY inside Heroku solved the issue.
If you've followed the Stephen Grider tutorial one thing I'm wondering: Is your passport.js file in config or services? I see you've written in index.js: require('./config/passport')
whereas mine in index.js is require('./services/passport')
may not be your solution to the google oauth flow hanging in production but may help.

How to add React to Express.js

I have got the basic files of express with express generator.
Now I want to add react to my express folder and integrate react with express. How can I do?
In your express file, you would need to link your react folder as static assets.
const express = require('express')
const path = require('path')
const app = express()
app.use(express.static(path.join(__dirname, 'client/build'))); // this is where your built react js files are
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname+'/client/build/index.html'));
}); // this makes sure that all paths access your react.js files
while in development, you can access your express app by adding a proxy option in your package.json
for example, when you start your express with
node index.js
It will be served at a localhost:3000 or something else when you specify another port like localhost:5000
In order to access the json or the data your express app is sending, you need to setup a proxy in your client's package.json. The proxy is used for data to be accessed, so before your client side connects to a localhost, it goes through that proxy to have access to data being sent
If for example, your express app is run at localhost:5000, add the following to your client sides package.json
"proxy": "http://localhost:5000"
so start your express app first then your react app, and you will have combined your react app with your express server.

Resources