Search code examples
reactjsnode.jsexpressnode-fetch

Why is my GET Request getting hung up in Node using Fetch


getDocuments request never completes/stays pending. What am I missing?

App.js

import React, { useState, useEffect } from 'react';
import Grid from './Grid';
import apis from '../api/index';

export default function App(props) {

  const [documents, setDocuments] = useState([]);

  useEffect(() => {

    async function initialize() {
      await apis.getDocuments().then(documents => {
        setDocuments(documents.data.data);
      });
    }

    initialize();
  }, []);
    
  return ( <Grid documents={documents} /> )
}

Controller.js

const fetch = require('node-fetch');

exports.getDocuments = async (req, res) => {
  // added 'return' before fetch
  return fetch('EXTERNAL API ENDPOINT', {
    method: 'GET',
    headers: {"api-key": "API KEY"}
  })
  .then(res => res.json())
  .then(json => {
    console.log(json);
    return json
  }).catch(err => console.log(err));
};

also tried this syntax:

//  added cors
exports.getDocuments = async () => {
  console.log("getting documents...");

  const response = await fetch(URL, {
    method: 'GET',
    mode: 'cors',
    headers: {
      "Content-Type": "application/json",
      "x-api-key": "KEY"
    }
  })

  const result = await response.json();
  console.log('result', result);
  return result;

};

server index.js

const express = require('express');
const cors = require('cors');

const { getDocuments } = require('./controllers/Controller');

const router = require('./routes');

const app = express();

//  enable CORS for all origins to allow development with local server
app.use(cors({credentials: true, origin: "http://localhost:3002"}));

app.use('/api', router);

app.get('/', (req, res) => {
    res.send('This is the backend/API');
})

app.set('port', process.env.PORT || 4200);
const server = app.listen(app.get('port'), () => {
  console.log(`Express running on port ${server.address().port}`);
});

enter image description here

with server on localhost: enter image description here


Solution

  • Assuming getDocuments is added to your /api router like this

    router.get("/getDocuments", getDocuments);
    

    Express does not use the return value of route handlers. Instead, you need to send a response.

    You need to change your controller to be like the following

    exports.getDocuments = async (req, res, next) => {
      console.log("getting documents...");
    
      const url = "EXTERNAL API ENDPOINT";
      try {
        const response = await fetch(url, {
          headers: {
            "x-api-key": "KEY",
          },
        });
    
        if (!res.ok) {
          // log details of unsuccessful responses
          console.error(
            "Fetch failed",
            url,
            response.status,
            await response.text(),
          );
          throw new Error("Failed to fetch from upstream");
        }
    
        // 👇 👇 👇 
        res.json(await response.json()); // send a response
        // 👆 👆 👆
    
      } catch (err) {
        // propagate the error to Express' error handlers
        next(err);
      }
    };
    

    Note, the try..catch is not required if using Express v5+