DEV Community

Cover image for React & REST API: How to overcome CORS errors
William Sayama
William Sayama

Posted on • Updated on

React & REST API: How to overcome CORS errors

In Part 2 of this series, we'll be making a REST API call from our React project to a service that has some CORS policies implemented. In this particular example, we'll make REST API calls to xkcd's API.

Make REST API calls to xkcd

What is xkcd?

xkcd is a webcomic series created by American author Randall Munroe. You can find the awesome comics here.

xkcd has an API?

Yes, it does indeed have an API.
You can find the great and concise API docs here.

What are we going to do?

We'll make REST API calls to one of my favorite comic strips that has an ID of 327, i.e. our endpoint will be https://xkcd.com/327/info.0.json. This will return JSON data about that particular comic strip.

Let's try calling it!

OK, so the implementation should be fairly simple. We made our REST API call to the Random User Generator API in our previous article - we just have to switch around the endpoint URL, right?

//const restEndpoint = "https://randomuser.me/api/";
const restEndpoint = "https://xkcd.com/327/info.0.json";
Enter fullscreen mode Exit fullscreen mode

OK that was super easy! Now let's refresh our React page.

Alt Text

...? Access to fetch at blah blah from origin bleh bleh has been blocked by CORS policy .... say what now???

Well, it looks like the response didn't render. And there seems to be a whole lot of red text in the console..._(┐「ε:)_

That error we see in the console is well known as the CORS Error. Basically, resources that lie on xkcd's domain cannot be requested from another domain (i.e. our front-end React App).

Alt Text

There are several ways we can overcome this issue:

  1. Make REST API calls from the same domain as xkcd
  2. Edit the CORS settings of xkcd's server
  3. Make REST API calls from our own backend server

We can quickly experience method 1 if we navigate to any page on xkcd, and run the following code in the console.

fetch('https://xkcd.com/327/info.0.json')
  .then(response => response.json())
  .then(data => console.log(data));
Enter fullscreen mode Exit fullscreen mode

Alt Text

The REST API request is being made on the same domain, so we don't run into any CORS errors. But it's highly unlikely that xkcd will host our React App on their site for us, so this isn't a realistic approach.

Method 2 again is unrealistic, since we don't have permission to access the settings of xkcd's server ¯\(ツ)

Method 3 is achievable by either setting up your own server and making requests from it, or using a services such as Zapier or Power Automate to make the requests for us.

In this article, we'll proceed with Method 3 by setting up a backend server using Express, which will act as a proxy to make REST API calls to xkcd.

Set up Express

What is Express?

Express is a back-end web application framework for Node.

How will we use Express?

In this article, we'll treat Express as a tool for creating custom endpoints that our front-end React App can make calls to. When we make requests to these custom endpoints, the Express server will make REST API calls to our desired 3rd party service endpoint, receive the response, and then route the response back to our React App.

If that was a bit hard to grasp, think of it like ordering food at a nice restaurant. If we (front-end App) go directly to the kitchen and order food directly to the chef (3rd party service), we'll be scolded for bad manners (CORS errors). What we need to do is order food to the server (Express App). The server (Express App) will take our order, walk to the kitchen, and request for the food to the chef (3rd party service). After some time, the chef (3rd party service) will respond by giving the server (Express App) back a plate of food. The server (Express App) then carries the plate back to the table so that we (front-end App) can consume it.

Set up Express

OK, so let's go ahead to set up Express. This is basically a new node project with the Express dependencies installed. We'll want this project to be in a separate location from our React App, so let's navigate back up to our myproject directory, create a new directory called backend, and navigate into it. Since the terminal we were using is running the React app, go ahead to use the commands in a new terminal window.

mkdir backend
cd backend
Enter fullscreen mode Exit fullscreen mode

From here we'll follow the Express installation tutorial to make our Express project.

npm init
Enter fullscreen mode Exit fullscreen mode

You'll be asked a number of questions but you can skip through them by hitting enter until it's finished.

Continue to install some dependencies.

npm install express node-fetch cors
Enter fullscreen mode Exit fullscreen mode

Finally, create a JavaScript file to work on - we'll call ours server.js.

touch server.js
Enter fullscreen mode Exit fullscreen mode

Alt Text

Set up the Express code

We'll use this code for server.js

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

const PORT = 5000;
const app = express();

app.use(cors());
const corsOptions = {
    origin: "http://localhost:3000"
};

const requestEndpoint = "https://xkcd.com/327/info.0.json";

// This function runs if the http://localhost:5000/getData endpoint
// is requested with a GET request
app.get('/getData', cors(corsOptions), async (req, res) => {
    const fetchOptions = {
        method: 'GET'
    }
    const response = await fetch(requestEndpoint, fetchOptions);
    const jsonResponse = await response.json();
    res.json(jsonResponse);
});

app.listen(PORT, () => {
    console.log(`Example app listening at http://localhost:${PORT}`);
});

Enter fullscreen mode Exit fullscreen mode

So, let's go through the code.

We first set our port to 5000, as we need it to be separate from the port we use on our front-end React App, which was defaulted to port 3000.

const PORT = 5000;
Enter fullscreen mode Exit fullscreen mode

Express commonly uses routing that defines how the server's endpoints will respond to our front-end React App's requests. In this case, we've defined how the server will react when the endpoint http://localhost:5000/getData is accessed with a GET request.

app.get('/getData', cors(corsOptions), async (req, res) => {
  //...
});
Enter fullscreen mode Exit fullscreen mode

But by default, our Express server will return CORS errors if accessed from our front-end React App that lies on a different domain (port). By setting up some CORS options, we allow requests from port 3000 to access our resources that lie on http://localhost:5000/getData.

app.use(cors());
const corsOptions = {
    origin: "http://localhost:3000"
};

app.get('/getData', cors(corsOptions), async (req, res) => {
  //...
});
Enter fullscreen mode Exit fullscreen mode

If we were to access http://localhost:5000/getData with a GET request from our React App, Express will run the related function, which in this case would be a fetch request to the xkcd REST API endpoint. As this request is made from the server side, it does not run in to any CORS errors. The response from xkcd is obtained, and returned back to our React App through the res.json() method.

const fetchOptions = {
    method: 'GET'
}
const response = await fetch(requestEndpoint, fetchOptions);
const jsonResponse = await response.json();
res.json(jsonResponse);
Enter fullscreen mode Exit fullscreen mode

OK, now that's ready, let's start running the express server!

node server.js
Enter fullscreen mode Exit fullscreen mode

We can quickly see if it's running successfully by accessing http://localhost:5000/getData through the browser. We should see the JSON response being displayed.

Alt Text

OK, so it looks like the Express App is making successful REST API calls to https://xkcd.com/327/info.0.json. Note that if we want to make any changes to server.js, we should restart the App to see the changes take place.

Let's leave the Express server running, and return back to our React code so that it points to the Express App rather than directly to the xkcd server.

Update the React code

There isn't much to do here, except for updating our REST endpoint to our Express server instead of the xkcd endpoint.

// const restEndpoint = "https://xkcd.com/327/info.0.json";
const restEndpoint = "http://localhost:5000/getData";
Enter fullscreen mode Exit fullscreen mode

Refresh the browser, and let's see if we've managed to bypass the CORS error.

Alt Text

Great! The REST API response has successfully rendered onto our HTML, and there are no CORS errors in our console.

And with that, we've managed to successfully avoid CORS errors to make REST API calls to xkcd by using our Express server as a proxy!

Next steps

In the next part of the series, we'll make a REST API call to a Web Database service, Kintone, which will challenge us to our next issue.

                   _人人人人人人人人人_
                   > AUTHENTICATION <
                    ̄Y^Y^Y^Y^Y^Y^Y^Y ̄
                   (\__/) 
                   (•ㅅ•) 
                   /つ つ
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
nonsodaniel profile image
nonsodaniel

Helpful👌🏼

Collapse
 
will_yama profile image
William Sayama

😁