1

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.

Looi
  • 96
  • 9
  • Have you read through this [answer](https://stackoverflow.com/a/30611910/8861638), it's a possible fix to _Cannot overwrite attachment values DATABASE_URL_ – Sultan H. Jul 20 '19 at 16:28
  • Yeah, and tried it too. I destroy the database, built a new one using the Heroku console, and got stopped from changing DATABSE_URL. There has to be a way to connect to the Heroku Postgres db as it is. Maybe it automatically generates some .env file that I have to target in my index.js file? – Looi Jul 21 '19 at 13:11
  • I admire that you are still trying to do this via Command Line, but to skip away the complixity that comes with it, why won't you try the online Heroku dashboard? – Sultan H. Jul 21 '19 at 16:13

1 Answers1

1

Update: This updated tutorial from Heroku did the trick: https://devcenter.heroku.com/articles/getting-started-with-nodejs#provision-a-database

For those looking for a sample implementation, check out what I did here: https://github.com/YFLooi/marketsurveyapp/blob/master/web/server.js https://github.com/YFLooi/marketsurveyapp/blob/master/web/db/queries.js


After awhile at trying to make this work, I decided on hosting my PostgreSQL db on an external site. Unlike Heroku Postgres, ElephantSQL offers the less difficult option of connecting to a db using a DATABASE_URL inside my project's .env file. I managed to connect my Heroku app to it and here's the result (the table which pops up on load):

https://github.com/YFLooi/test4heroku

Credit goes to this tutorial for showing me the ropes:

https://www.fullstackagile.eu/2017/06/04/js-sql-fullstack-guide/

Looi
  • 96
  • 9