I'm currently working on a project using React (via create-react-app
) and JSONServer for the API.
I have a single Git repository structured as follow :
|-- client
|-- api
To work in a dev environment, I start both of the folders with npm start
in order to have http://localhost:3000 for the React app and http://localhost:3001 for the API.
This way (thanks to Axios) I can connect to http://localhost:3001/api to retrieve my content
import axios from 'axios'
export default axios.create({
baseURL: 'http://localhost:3001/api'
})
Everything works great so far.
Now I want to deploy my app and API to Heroku and this is where things get complicated.
So here's my questions and it would be very helpful to have some advice on what is the best way to handle it:
- Should I create two apps on Heroku ? One for the client and one for the API?
- If I have two apps on Heroku, how can I reach the API safely from the client? Maybe fetching the url of the API app (like https://myapp.herokuapp.com/api) but I'll have to deal with CORS issues.
- Or should I create only one app with API and put the client's build in the same folder/url (Eg. : serving public files of the build with JSONServer)
For the moment, I have a server.js
file at the root of my client's folder and a Procfile
with web: node server.js
to launch a server for the build. Then I fetch data with Axios from another Heroku app (which is actually the API app).
Any advice/help will be very appreciated! Thanks!
P.S.: here's my package.json ans server.js files for client and api
Client's server.js (at the root of client's folder)
const express = require('express')
const http = require('http')
const path = require('path')
const app = express()
app.use(express.static(path.join(__dirname, 'build')))
const port = process.env.PORT || '8080'
app.set('port', port)
const server = http.createServer(app)
server.listen(port, () => console.log(`Running on localhost:${port}`))
Api's server.js (at the root of api's folder)
const express = require('express');
const jsonServer = require('json-server');
const router = express.Router();
const server = jsonServer.create();
const mainRoute = jsonServer.router('db.json');
const middlewares = jsonServer.defaults({ noCors: false });
const port = process.env.PORT || 3001;
router.use('/api', mainRoute)
server.use(middlewares);
server.use(router);
server.listen(port);
Client's package.json:
{
"name": "portfolio",
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/core": "^10.0.28",
"@emotion/styled": "^10.0.27",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"axios": "^0.19.2",
"express": "^4.17.1",
"google-spreadsheet": "^3.0.11",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-intl": "^4.6.3",
"react-lazyload": "^2.6.8",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"postinstall": "react-scripts build"
},
"proxy": "https://my-api.herokuapp.com/api",
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"eslint-plugin-react": "^7.20.0",
"react-spring": "^8.0.27",
"standard": "^14.3.4"
}
}
Api's package.json:
{
"name": "json-server-heroku",
"version": "1.0.0",
"description": "Simple json-base database to deploy to Heroku",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js",
"fetch": "node fetch-data.js"
},
"keywords": [
"json-server,heroku, node, REST API"
],
"author": "Jesper Orb",
"license": "ISC",
"dependencies": {
"google-spreadsheet": "^3.0.11",
"json-server": "^0.16.1"
}
}