4

How do connect to multiple APIs with React App?

Create-react-app with Express backend, using http-proxy-middleware.

Demo bug : https://github.com/svgpubs/nodeproxy.git

I am using http-proxy-middleware to try to connect a demo React App to two different servers: one external website https://api.coingecko.com/api/ and one internal site http://localhost:3001/

It works for the external website. However, localhost:3001 connection doesn't work.

I can connect to the localhost:3001 if I don't use http-proxy-middleware (by adding 'proxy: 'http://localhost:3001'" in package.json) - however, then I can only have one proxy.

Here is the app running: as you can see, there is no response from localhost:3001

enter image description here

Errors: I've tried so many different variations. I either get a cors block from the browser, or the localhost api returns index.html file from public/index.html - resulting in a json parsing error in the browser. On the server, depending on the exact route for localhost endpoint, I sometimes get 50+ lines of this error: Error occurred while trying to proxy request /localhostapi/users from localhost:3001 to http://localhost:3001/ (ECONNRESET) (https://nodejs.org/api/errors.html#errors_common_system_errors)

How do I setup the server and proxy so that App.js can connect to both localhost:3001 routes AND external APIs?

Here is my App.js

import React, { useEffect, useState } from "react";
import "./App.css";

function App() {
  const [externalServerResponse, setExternalServerResponse] = useState(
    "no response"
  );
  const [localhostServerResponse, setLocalhostServerResponse] = useState(
    "no response"
  );

  const getExternalAPI = async () => {
    console.log("calling external api from client");
    const result = await fetch("http://localhost:3001/api_to_external_website");
    console.log("result", result);
    const data = await result.json();
    console.log("data", data);
    setExternalServerResponse(JSON.stringify(data[0]));
  };

  const getLocalHostAPI = async () => {
    console.log("calling localhost api from client");
    const result = await fetch("/localhostapi"); //I've tried many syntax variations 
    console.log("result", result);
    const data = await result.json();
    console.log("data", data);
    setLocalhostServerResponse(JSON.stringify(data));
  };

  useEffect(() => {
    getExternalAPI();
    getLocalHostAPI();
  }, []);

  return (
    <div className="App">
      <div style={{ marginTop: "3em", marginBottom: "1em" }}>
        <h2>
          Response from{" "}
          <code>
            <i>www.api.coingecko.com/api</i>
          </code>
          :
        </h2>
      </div>
      <div>{externalServerResponse}</div>
      <div style={{ marginTop: "3em", marginBottom: "1em" }}>
        <h2>
          Response from{" "}
          <code>
            <i>localhost:3001</i>
          </code>{" "}
          :{" "}
        </h2>
      </div>
      <div>{localhostServerResponse}</div>
    </div>
  );
}

export default App;

Here is server.js

const express = require("express");
const { createProxyMiddleware } = require("http-proxy-middleware");
const port = 3001;

const app = express();

app.use(
  "/api_to_external_website",
  createProxyMiddleware({
    target:
      "https://api.coingecko.com/api/v3/coins/markets?vs_currency=USD&order=market_cap_desc&per_page=100&page=1&sparkline=false",
    headers: {
      accept: "application/json",
      method: "GET",
    },
    changeOrigin: true,
  })
);

app.use(
  "/localhostapi",
  createProxyMiddleware({
    target: `http://localhost:${port}/`,
    headers: {
      accept: "application/json",
      method: "GET",
    },
    changeOrigin: true,
  })
);

app.get("/", (req, res) => {
  console.log("localhost:3001 api is running");
  const data = { result: `Success! from localhostapi on localhost:${port}!!` };
  res.send(JSON.parse(data));
});

app.listen(port, function () {
  console.log(`server running now.. ${port}`);
});

How do I set up my server and proxy so that my App.js can get both localhost:3001 routes AND external APIs?

Instructions to run app:

In one terminal: make a folder, clone nodeproxy app, install dependencies, then run server

mkdir newfolder
cd newfolder
git clone https://github.com/svgpubs/nodeproxy.git
npm install
node server.js

Then, keeping the first terminal running, open a second terminal window: go to that same folder and start the react app.

cd newfolder
npm start 

List of things I've tried:

  1. Using additional package.json attribute "proxy: 'localhost:3001'

  2. src/setupProxy.js

const { createProxyMiddleware } = require("http-proxy-middleware");

module.exports = function(app) {
app.use(
  "/localhostapi",
  createProxyMiddleware({
    target: `http://localhost:${port}/`,
    headers: {
      accept: "application/json",
      method: "GET",
    },
    changeOrigin: true,
  })
);
}

  1. changing fetch and app.use syntax

[![enter image description here][3]][3]

1
  • found a workaround by changing the folder structure. see answer below Commented Sep 15, 2020 at 8:20

1 Answer 1

2

I figured out that changing my project folder structure did the trick. Not only can I connect to external website APIs, as above, but I can connect to two+ different ports on my localhost as shown here.

What I think the problem was: My server.js file was in the same directory as the front-end package.json file, which contained the http-proxy-middleware dependency.

Here is the app code on github https://github.com/svgpubs/react-with-multi-apis

This was my incorrect folder structure:

.
├── package.json
├── node_modules
├── public
├── server.js
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    ├── serviceWorker.js
    ├── setupProxy.js
    └── setupTests.js

The remote api server.js file(s) should not be in the same folder as front-end package.json with http-proxy-middleware listed as dependency. (It might have been that the proxy was attempting to proxy the server to itself. But I might be wrong.)

I rearranged the project to have this structure - which works:

.
├── api1
│   ├── package.json 
|   ├── node_modules
│   └── server1.js
├── api2
│   ├── package.json
|   ├── node_modules
│   └── server2.js
└── reactapp
    ├── node_modules
    ├── package.json
    ├── package-lock.json
    ├── public 
    └── src
        ├── App.css
        ├── App.js
        ├── App.test.js
        ├── index.css
        ├── index.js
        ├── logo.svg
        ├── serviceWorker.js
        ├── setupProxy.js
        └── setupTests.js

enter image description here

setupProxy.js

const { createProxyMiddleware } = require("http-proxy-middleware");

module.exports = function (app) {
  app.use(
    "/api1",
    createProxyMiddleware({
      target: "http://localhost:3080",
      changeOrigin: true,
    })
  );
  app.use(
    "/api2",
    createProxyMiddleware({
      target: "http://localhost:3070",
      changeOrigin: true,
    })
  );
  app.use(
    "/api_to_external_website",
    createProxyMiddleware({
      target:
        "https://api.coingecko.com/api/v3/coins/markets?vs_currency=USD&order=market_cap_desc&per_page=100&page=1&sparkline=false",
      headers: {
        accept: "application/json",
        method: "GET",
      },
      changeOrigin: true,
    })
  );
};

api1/server1.js

const express = require("express");
const bodyParser = require("body-parser");
const port = 3080;
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));

app.get("/api1", (req, res) => {
  console.log(`localhost:${port} api is running`);
  const data = {
    result: `Success! from localhost on localhost:${port}!!`,
  };
  res.send(data);
});

app.listen(port, function () {
  console.log(`server running now.. ${port}`);
});


api2/server.js is identical execpt for port is 3070, and api1/ is api2/

Sign up to request clarification or add additional context in comments.

1 Comment

I'm running a server on http://localhost:8000 and my react app on http://localhost:3000. In my setupProxy.js I've set the path to /api and the target to http://localhost:8000/ but for some reason in my react app it hits the url http://localhost:3000/api. Any idea how I can get around this?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.