In an exercise to learn React I’ve been building a single page client side app in React that consumes my Harvest Helper API and provides a responsive user interface not far from the original one built in Rails.
When I initially began making API calls to my Harvest Helper API from my client side app using fetch (not supported on mobile yet but should be the new AJAX standard in a couple of years — use jQuery.ajax for now), I would get errors in the console that looked like this:
Fetch API cannot load http://harvesthelper.herokuapp.com/api/v1/plants?api_key=fd4145533949c711dab5d31e1d10187d. Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8080' is therefore not allowed access. The response had HTTP status code 404. If an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.
What is CORS, you might ask? Cross Origin Resource Sharing (CORS) gives web servers cross domain access controls, which enables secure cross-domain data transfers. Modern browsers use CORS in an API container, such as XMLHttpRequest (what fetch and jQuery.ajax use under the hood), to mitigate the risks of cross-origin HTTP requests.
Alright, so in reading the error, it looks like I have 2 options in navigating this CORS business:
- Set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled. This will return an opaque response.
- Add an ‘Access-Control-Allow-Origin’ header to my rails server.
An opaque response is a filtered response whose type is “opaque”, url list is an empty list, status is 0, status message is the empty byte sequence, header list is the empty list, body is null, and cache state is “none”. This is essentially useless considering that my entire React app is dependent on getting data from my Rails API.
Knowing that an opaque response isn’t going to get me anywhere, it looks like I’m going to need to add an ‘Access-Control-Allow-Origin’ header to my rails server. Luckily this gentleman decided to make a gem for my very problem, called rack-cors, which is incredibly easy to use. Simply add the gem to your gemfile:
gem 'rack-cors', :require => 'rack/cors'
and something like this in your config/application.rb file if you are using Rails 3 or 4:
class Application < Rails::Application
config.middleware.insert_before 0, "Rack::Cors" do
resource '*', :headers => :any, :methods => [:get, :post, :patch, :options]
That’s it. You’re all set. No more errors should be coming your way from not being able to navigate CORS when making calls to your Rails API. If you are using Rails 5 or have any other questions in using the rails-cors gem, the docs are great.