0

I'm trying to send data to my Nodejs server (hosted on Firebase), from Reactjs to retrieve data from an API call.

It worked when the API url was hard coded, so the issue should be in sending the data from React to Node. I'm currently trying to have it only return one request, but once I'm able to do that, I will be trying to fetch multiple requests.

The result is to populate the stocks state with the response.

My React code looks like this:

class Table extends Component {
  constructor (props)
  {
     super(props);
      this.state = {
         favorites: ['APPL'],
         stocks: []
     };
 }

   componentDidMount() {
   // http is adjusted for stackoverflow
    fetch('http://localhost:5001/', { 
      // new part:
      method: 'post',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({
        favorites: this.state.favorites})
      // old part - worked before i tried to send data to the backend:
    })
    .then((response) => response.json())
    .then(stockList => {
        this.setState({ stocks: stockList });
            console.log(stockList);
    });
}

Node code:

const functions = require("firebase-functions");
const express = require("express");
const fetch = require("node-fetch");
const cors = require("cors");

    const app = express();
    app.use(cors({origin: true}));
    
    app.get('/', async (request, response) => {
      // new line that was ment to catch the data from frontend.
      const favorites = request.body.favorites
      // web and key is the rest of the API call.
      const url = web+favorites+key;
      const fetchResponse = await fetch(url);
      const symbol = await fetchResponse.json();
      response.json(symbol);
    });
Binne
  • 19
  • 1
  • 9
  • You say it worked before with a hardcoded URL, does it not work now? If not, what error are you getting or what is not working? I also noticed that you're sending a POST request in your React code but your route in the Node code is for a GET request (app.get instead of app.post), is that correct? – Álvaro Zamora May 31 '21 at 10:00
  • Hi @ÁlvaroZamora, the issue seems to be that i'm not sending the data from react to node, which leads to this error: UnhandledPromiseRejectionWarning: FetchError: invalid json response body at https://sandbox.iexapis.com/stable/stock/undefined/quote?token=. I have removed the token, but if you see the undefined in the middle, that should be "aapl" (it is wrong in the posted code, but i have corrected it.) I'm using a post in react to send data to node and edit the url that is send to iexcloud, but I do not know if that is the way to do it. – Binne May 31 '21 at 11:20
  • Oh I think I see what you're trying to do. React sends the data to Node through a POST request and Node makes a GET request to that API you just linked to get information. In this case you would be missing a POST endpoint in your Node code to get the data, no? I believe you're mixing two different requests into one. – Álvaro Zamora May 31 '21 at 12:08
  • @ÁlvaroZamora Yes exactly. TBH, I have no idea what I'm doing wrong. Do you have an idea on how to solve it? I'm not sure how i would be adding a POST endpoint in the Node code. – Binne May 31 '21 at 12:25
  • @ÁlvaroZamora like so?: app.post('/', (request, response) => { // here is how you get the POST data from the body const favorites = console.log(req.body.favorites) // send the data from the POST request to the API through a GET request here app.get('/', async (request, response) => { // const favorites = request.body.favorites; // console.log(favorites) const url = web+favorites+key; const fetchResponse = await fetch(url); const symbol = await fetchResponse.json(); response.json(symbol); }); }) – Binne May 31 '21 at 13:22

3 Answers3

0

In order to get the data from the frontend you will need to make a post endpoint instead in your Node server and send a GET request inside that method.

const functions = require("firebase-functions");
const express = require("express");
const fetch = require("node-fetch");
const cors = require("cors");

    const app = express();
    app.use(cors({origin: true}));
    
    app.post('/', (req, res) => {
        // here is how you get the POST data from the body
        console.log(req.body.favorites)
        
        // send the data from the POST request to the API through a GET request here

    })

Now you need to make a GET request where I put the comment, you can use the simpler https node.js library for that.

0

In my question, I'm trying to use Firebase functions to handle the link to an external API and use the data from that API in my frontend.

After some though and help from Stackoverflow, I have found that it might not be an ideal way to do it. I was basically trying to add a layer between the frontend and the API, but that is not necessary, as it is possible to reach the API directly in React. This will remove the function from Firebase, meaning less steps, less code and less fees.

So for every instance in the state.favorites, the correlated data is pulled from the API and stored in the state.stocks.

This piece of code did the trick:

class Table extends Component {
  constructor (props)
  {
     super(props);
      this.state = {
         favorites: ['aapl', 'arvl'],
         stocks: []
     };
 }

      componentDidMount() {
        this.state.favorites.map((favorites, index) => {
        fetch(`API_website${favorites}/(API_token`)
            .then((response) => response.json())
            .then(stockList => {
               this.setState({ stocks: stockList });
                   console.log(stockList);
           });
        })
      }
Binne
  • 19
  • 1
  • 9
-1

fetch need import if you have new version.

const fetch = import("node-fetch");

Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 26 '23 at 13:58