If like me, you’re new to React and developing an app with a database that’s on another server you will have run into the error,

Fetch API cannot load ‘url’. No 'Access-Control-Allow-Origin' header is present on the 
requested resource. Origin ‘url’ is therefore not allowed access. If an opaque response serves 
your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

This is caused by the app being hosted under a different host to that of the database. This can be annoying as you may only need to access the database from a different host during development, while in production you plan to deploy the app alongside the database. If this is the case this article will explain how to get around this error message. If, however you plan to use the app in production on a different host to the database this solution will not, for this you’ll either need to disable CORS server side or create a proxy server that connects to the remote connection and serves the content.

TL;DR

Use the proxy setting in the package.json, use this example project as a quick implementation guide.

Same Origin Policy

The same origin policy allows the blocking of content from other hosts, protocols and sometimes port (depending on the implementation in the browser), at the browser level. Although this can be annoying for developers, it’s an important security model as it protects the end user from malicious code.

For example, consider a user that has active sessions with multiple sites, these sessions will be kept active with the session cookies if the user hasn’t logged out of the site. If the user then visits a site containing malicious JavaScript without the same origin policy enabled, the script can obtain data the user believes to be secure from the previous sites. Although JavaScript has no access to session cookies from the other site, it can still send and receive request from these sites and be authenticated based on the session cookie.

If you own the server and you don’t handle any secure data it may be a valid option to enable CORS using the CORS response headers. This will allow browsers to request data from your server while on another host/protocol/port.

Solution

Many solutions posted online recommend either using a plug-in to disable CORS or disabling security within the browser. Both of these solutions are potentially dangerous and completely unnecessary. Even if you have a dedicated browser for development, it’s easy to forget this and navigate to another page. A better solution is built into React itself, React will act as a proxy server during development (when using npm start) if the proxy setting is supplied within the package.json.

For some reason this doesn’t seem to be a well-known feature (as shown by the amount of bad advice on this problem) even though it’s been available since react-scripts 0.2.3.

Here you set your server url and can ignore CORS while in development. This feature only works when working in development (when using ‘npm start’) and takes the place of your host, therefore making sure your endpoints point to the correct place in development and production without requiring code changes.

An example project demonstrating this can be found here. This example requests and displays the latest comic from xkcd, using their public API https://xkcd.com/info.0.json. I picked xkcd because it has cross origin resource sharing disabled. If you attempt to access it directly you will receive the CORS error message, however using the package.json, this is ignored.

In your app the package json should include the host in the proxy setting. i.e for xkcd it should be “https://xkcd.com/”


{
  "name": "react_cors_demo_project",
  "version": "0.1.0",
  "dependencies": {
    ...
  },
  "scripts": {
    ...
  },
  "eslintConfig": {
    ...
  },
  "browserslist": [
    ...
  ],
  "proxy": "https://xkcd.com/"
}


and the endpoint in the request shouldn’t include the host. Here the endpoint “info.0.json” returns the meta data for xkcd’s latest comic

 
fetch('info.0.json')
.then(response => response.json())
.then(data => console.log(data))
.catch(() => console.log('Error fetching data'))

This allows you to work in development and deploy to production without the need to change any endpoint between environments.