- Create an API-Only Rails Build
In the last few lessons, we saw how we can easily adapt the MVC structure of Rails to render JSON. Rails is flexible enough to be able to respond to different formats, and is ready to do so out of the box. For the purposes of building applications in JavaScript and frameworks like React, though, we specifically need it to act as an API that responds with JSON.
When first building a Rails application, it is possible to flag that the application should be API-only. In this lesson, we will take a look at what this means and how it provides us with some useful automatic configurations.
To create an API-only Rails build from scratch, include the --api
after the
name of the Rails application name upon creation:
rails new bird-watcher-api --api
By using the --api
flag, Rails will remove a lot of default features and
middleware, mostly related to the browser, since it won't be needed. Controllers
will inherit from ActionController::API
rather than ActionController::Base
and generators will skip generating views.
One noticeable change - some browser errors will disappear. Normally, when a Rails server is running, it produces an error message in browser when something goes wrong while attempting to render. Since there is no way to render views in this API-only build, if the Rails API fails and we visit it in browser, it will just show a blank screen.
No changes are required when setting up resources for an API-only Rails build.
We've gone over the pieces of building an API, so to briefly summarize what we've done in the last few lessons combined with this new knowledge, first we create the API-only Rails build:
rails new bird-watcher-api --api
Then, navigate into the new Rails application once created. Rather than create everything by hand this time, we can use a generator to help us out with resources.
rails g resource bird name species
rails g resource location latitude longitude
rails g resource sighting bird:references location:references
This will create three migrations, three models, and three empty controllers. With minimal seed data we could then test that everything was working as expected:
bird_a = Bird.create(name: "Black-Capped Chickadee", species: "Poecile Atricapillus")
bird_b = Bird.create(name: "Grackle", species: "Quiscalus Quiscula")
bird_c = Bird.create(name: "Common Starling", species: "Sturnus Vulgaris")
bird_d = Bird.create(name: "Mourning Dove", species: "Zenaida Macroura")
location_a = Location.create(latitude: "40.730610", longitude: "-73.935242")
location_b = Location.create(latitude: "30.26715", longitude: "-97.74306")
location_c = Location.create(latitude: "45.512794", longitude: "-122.679565")
sighting_a = Sighting.create(bird: bird_a, location: location_a)
sighting_b = Sighting.create(bird: bird_b, location: location_b)
sighting_c = Sighting.create(bird: bird_c, location: location_c)
Then the controller actions we want in the API will need to be added:
def index
sightings = Sighting.all
render json: sightings, include: [:bird, :location]
end
Since the resource
generator was used, it would be good to be diligent and
clean up config/routes.rb
once we've decided what endpoints the API should
have.
While working on your own APIs, you'll typically want to have your Rails server
running while also trying out various endpoints using fetch()
. In order to do
this, though, you will need deal with Cross-Origin Resource Sharing, or CORS.
CORS is designed to prevent scripts like fetch()
from one origin accessing a
resource from a different origin unless that resource specifically states that
it expects to share. So, for instance, if you have run the command rails server
with your server running at http://localhost:3000
, then go to
'www.google.com,' open the browser console and attempt to send a fetch()
to your
server. The browser considers these two different origins, and will refuse
your request.
A solution is already provided though. By using the --api
flag, the Gemfile
was altered to include the rack-cors
gem. The gem will be commented out initially:
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
# gem 'rack-cors'
To get rack-cors
working, uncomment the gem and run bundle install
. Then, add the following to
config/application.rb
inside class Application < Rails::Application
:
config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*'
resource '*', headers: :any, methods: [:get, :post]
end
end
This shouldn't replace anything else inside class Application < Rails::Application
,
just be included in addition.
This will allow you to test your APIs while developing them locally. Secretly,
rack-cors
has been bundled with the last set of lessons to ensure they were
all working smoothly in case you decided to code along and spin up a rudimentary
API.
WARNING: Disabling CORS altogether in the long term can leave your server
unsecure. Check out the documentation on CORS and rack-cors
for
additional information.
With CORS enabled and your resources configured, you should be able to now
run rails server
, start up your API and begin sending requests to it.
You have all that you need to get your own API-only Rails builds into development. If you can think of something that can be turned into an API, you now the power to spin one up in short order.
With the ability to create APIs, we will take a closer look at shaping them.