I wanted to write a quick post on hooking up a
create-react-app React app in development with a Rails API backend server also in development, and specifically the frustrating Cross-Origin Resource Sharing error that will often pop up in the console these situations:
For the purposes of this post, I'll assume that we have the
create-react-app development server running on
localhost:3000, letting us view our app in the browser with hot reloading whenever we change our files. I'll also assume that we have our API server running on
The problem arises when we try to
fetch data from our backend from our React app, since the browser considers different
localhost ports to be different origins. MDN has a good explanation of what CORS is, if you'd like further information - essentially, it's a "mechanism that uses additional HTTP headers to let a [browser] gain permission to access selected resources from a server on a different origin (domain) than the site currently in use." Cross-origin requests without these headers are blocked for security reasons.
Fortunately for us, there's a really simple solution to let us access our backend API server from a
create-react-app React application without even dealing with CORS headers: we can just add a proxy to our React server to redirect the appropriate requests to the backend.
First, we'll need to make sure the urls we're fetching do not include the absolute path (i.e.
http://localhost:3001). So if we ultimately want to hit the
http://localhost:3001/items endpoint, we would just use the url
/items in our call to the backend.
Next, we can add a proxy setting in package.json:
// other settings... "proxy": "http://localhost:3001/" // other settings...
With this setup, the
create-react-app configuration will pass on any requests which are not static assets and where the URL is not recognized. The browser won't give any CORS errors because as far as it knows it's just connecting with the same Webpack server that's serving the React app.
To be clear, if we've set up a proxy in React that's working the way we want it to, we don't need to touch Rails at all. The proxy should work great as long as the frontend and API will be on the same domain in production.
However, if we don't want to use the proxy for some reason, or if our production API is on a different domain than our React app, it's useful to know how to set up CORS headers in Rails as well.
If we're using Rails 5 and created our app with the
--api flag, all we need to do is uncomment
gem rack-cors in our
Gemfile, then uncomment the following code in
Rails.application.config.middleware.insert_before 0, Rack::Cors do allow do origins 'localhost:3000' resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head] end end
origins allows the frontend server at that specific URL to retrieve data from our backend, but we can change it to whatever we want. We can also add an additional
allow do block beneath the first if we want to specify more than one allowed origin.
As an aside, we'd obviously want to change the backend calls in our React app to absolute rather than relative paths, since we're now calling our backend at a different origin - as the above setup has allowed us to do - rather than proxying the requests.