3
votes

I am hosting a React app with an Express backend on Firebase Hosting. While the local version works like a charm, making calls to my Express API yields 404.

The relevant parts of my file tree are as follows;

Project
 | - client // On deploy we use client/public as public folder
       | - public 
       |      | - index.html 
       | - src
       |      | - App.js // React app here
       |      | - Chat.js // Calls to API made here
       | - package.json
 | - firebase.json
 | - package.json
 | - server.js // Express API functions here

In my component Chat.js I make the following call:

    fetch("/api/input", {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(this.state),
    })
        .then(res => res.text())
        .then(
            res => { .... // get response from the API  

To redirect this call from the React app hosted at http://localhost:3000, to the Express app that is locally hosted at :5000, my client/package.json includes

  "proxy": "http://localhost:5000/",

And indeed, when locally hosted, a POST request to "http://localhost:3000/api/input" yields the expected result.

As for server.js, it includes the following:

const express = require('express');
...
var firebase = require("firebase");
const functions = require('firebase-functions')
...
const app = express();
const port = process.env.PORT || 5000;
...
app.post('/api/input', async (req, res, next) => { ... }) // Here's the relevant API call
...
exports.app = functions.https.onRequest(app) // export to firebase functions ('app')

Then, firebase.json is as follows:

{
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "hosting": {
    "public": "client/build",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "/",
        "destination": "/index.html"
      },
      {
        "source": "/api/**",
        "function": "app" //should make sure that calls to the API are getting to the Express app
      }
    ]
  }
}

When deploying the site using firebase deploy, the call to /api/input yields: enter image description here

enter image description here

Which steps may I have missed that prevents API calls from reaching my Express API?

(Something I can imagine is that firebase deploy only deploys the built frontend, but not sure how to fix that)

2
app.post('/api/input') should be app.post('/input') - OmG3r
Tried it... changed nothing here. What does change that in that case, my locally hosted application then gives the error Proxy error: Could not proxy request /api/input from localhost:3000 to http://localhost:5000/ (ECONNREFUSED) onfetch. - Teresa
on your localhost you should request at localhost:5000/input , while on firebase you need to request guidedduckbot-fogccm.web.app/api/input - OmG3r
Okay, in case in React I fetch("/input", { and in express I set app.post('/api/input') to app.post('/input') (everything else the same as above), that leaves me with the Proxy error on localhost and the same 404 on Firebase. So what other step would I then need to take? - Teresa
I solved the proxy error on localhost (unrelated issue). Other than that, no progress on Firebase. - Teresa

2 Answers

0
votes

You may forget configs for production. inside your server-side app.js

const path = require('path')

the path is inside of node core so you don't need to install it.

if(process.env.NODE_ENV === 'production'){
app.use(express.static('client/build'))

app.get('*', (req, res) => {
    res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'))
})
}
0
votes

Firebase doesn't support nodejs+express apps.

It primarily hosts static content; in order to run server code you will want to look into cloud functions..