I'm setting up a test website on Heroku consisting of React and Heroku Postgres with Express to join the two together. On componentDidMount(), the React portion makes two fetch() requests through Express. The first returns a response.send() and the second connects to the Heroku Postgres app I have set up to pull an array of book titles for rendering into a list. Instead of GET-ing the data I requested, Heroku returned this console message:
Request failed SyntaxError: Unexpected token < in JSON at position 0 at App.js:14 NewArrivals:1 Failed to load resource: the server responded with a status of >503 (Service Unavailable)
I believe the first error message relates to the first fetch() request and the second for the second fetch() request. The React app did load however.
Prior to attempting the connection, I pushed data to this Heroku app's Heroku Postgres using the following:
cat db/data.sql | heroku pg:psql -a testapp
and checked to find the data I pushed is in the database.
I am using the Heroku recommended approach of using Client instead of Pool in index.js. Some stackoverflow channels recommended setting DATABASE_URL to fix the Express connection to Heroku Postgres. My attempt at this using the Heroku CLI returned 'Cannot overwrite attachment values DATABASE_URL'
Here's the code for each part of the website, and their package.json files. I have organised my files in the following order:
/root (Contains all files, including index.js and the package.json file to support index.js)
/root/db (Contains queries.js which handles the Heroku Postgres GET request together with index.js)
/root/client (Contains the files from create-react-app)
/root/package.json
{
"name": "testapp",
"main": "index.js",
"dependencies": {
"body-parser": "^1.19.0",
"cors": "^2.8.5",
"dotenv": "^8.0.0",
"express": "^4.17.1",
"express-promise-router": "^3.0.3",
"path": "^0.12.7",
"pg": "^7.11.0"
},
"engines":{
"npm": "6.4.1",
"node": "10.15.3"
},
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1",
"heroku-postbuild": "npm install && cd client && npm install && npm run build"
},
"license": "ISC"
}
/root/index.js
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
const path = require('path');
const port = process.env.PORT || 5000;
const db = require('./db/queries.js')
app.use(bodyParser.json())
app.use(express.static(path.join(__dirname, 'client/build')));
app.get("/", async (request, response) => {
if (error) {
throw error
}
response.send("Server running on Node.js, Express, and Postgres API")
})
app.get("/NewArrivals", db.getNewArrivals)
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname+'/client/public/index.html'));
})
app.listen(port, () => {
console.log(`App running on port ${port}.`)
})
/root/.env
PGHOST=localhost
PGUSER=me
PGDATABASE=booklibrary
PGPASSWORD=x
PGPORT=5432
/root/db/queries.js
const { Pool, Client } = require('pg')
const connectionString = process.env.DATABSE_URL;
const client = new Client({
connectionString: connectionString,
ssl:true,
})
require('dotenv').config();
client.connect()
const getNewArrivals = (request, response) => {
client.query('SELECT * FROM newarrival ORDER BY id ASC', (error, results)
=> {
if (error) {
throw error
}
response.status(200).json(results.rows)
client.end();
})
}
module.exports = {
getNewArrivals
The contents of the /root/client folder are exactly like the output of the create-react-app. The exception is App.js which I modified as follows:
import React from 'react';
import { useEffect, useState } from 'react';
import logo from './logo.svg';
import './App.css';
function App(props) {
let [cards, setCards] = useState([])
//Runs on ComponentDidMount()
useEffect(() => {
//Obtains data from PostgreSQL db for renderData
fetch('/', {method:"GET"})
//Here I call 2 promise functions: The first fetches data
(response), the second examines text in response (data)
.then(function(response){
return response.json()
//Examines data in response
.then(function(data){
console.log(data)
})
}).catch(function(error){
console.log('Request failed', error)
})
//Obtains data from Heroku Postgres db for renderData
fetch('/NewArrivals', {method:"GET"})
.then(function(response){
return response.json()
//Examines data in response
.then(function(data){
console.log(data)
renderData(data)
})
}).catch(function(error){
console.log('Request failed', error)
})
}, []);
//Generates list of book titles
const renderData = (data) => {
cards.splice(0, cards.length);
let newCards = [];
newCards.splice(0, newCards.length);
for(let i=0; i<4; i++){
let card = [
<div key={`card.${i}`} style={{width: '100%', height: 'auto',
border:'1px solid white'}}>
{data[i].title}
</div>
]
newCards = [...newCards, ...card]
}
setCards([...newCards])
}
return (
<div className="App">
<header className="App-header">
<div>
Titles available:
{cards}
</div>
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
I'm sure I missed something in getting Heroku Postgres to talk to Express. Thanks in advance.