Building APIs with Grape

Grape is a micro-framework for building APIs with Ruby. It enables you to quickly build and iterate on your API alongside your existing Rails or Sinatra application, as well as on it’s own as a standalone API.

It gives you versioning, entities, validations, and importantly easy ways to document your API as you build it (please do this last thing in particular) all out of the box. For the extra stuff you need, there’s a metric tonne of 3rd-party gems available to utilise.

Let’s take a bit of a look at how you might build an API using grape as a standalone product:

Getting started is, as always pretty easy in Ruby land, just add grape to your gemfile


# Gemfile

gem 'grape'

If you find yourself wanting to mount the API alongside your existing Rails or Sinatra application, take a quick look at the below samples for working with the router:

# Rails

# config/routes.rb

mount AwesomeCompany::API => '/'

# Using rails 4? youll need the hashie rails gem if working with activerecord so you can bypass strong params and use grapes params validation instead

# Sinatra

# config.ru

use Rack::Session::Cookie
run Rack::Cascade.new [API, Web]

For our standalone application, our setup could not be simpler


# config.ru

run AwesomeCompany::API

So now that we have grape installed and have our application ready and waiting to go, lets get started defining some resources and actually building our API. Whilst grape doesn’t have any strong opinions on how you should structure your code, I personally prefer to house my API files in a controller directory, so let’s start there:


# /lib/controllers/api/base.rb

module AwesomeCompany
  module API
    class Base < Grape::API
      prefix :api # set the url prefix
      format :json # define the format
      mount AwesomeCompany::API::V1::Base
    end
  end
end

Our base file’s job is purely to declare some ground rules for the different versions of our API and to make available those versions if it receives an appropriate request. Let’s dive a little deeper now, and take a look at how our API can make some resources and end-points available for our users to consume.

# /lib/controllers/api/v1/base.rb

module AwesomeCompany
  module API
    module V1
      class Base < Grape::API
        mount AwesomeCompany::API::V1::Companies      
        mount AwesomeCompany::API::V1::Employees              
      end
    end
  end
end  

# /lib/controllers/api/v1/companies.rb

module AwesomeCompany
  module API
    module V1
      class Companies < Grape::API
      end
    end
  end
end  

So all we’ve done above is simply define which resources are available as part of the first version of our API. Currently our companies resource isn’t doing much, let’s setup an end-point so we can retrieve a list of companies.


# /lib/controllers/api/v1/companies.rb

module AwesomeCompany
  module API
    module V1
      class Companies < Grape::API
      	params do
      	  optional :name, type: String, desc: 'Company name you wish to filter on'
      	end
      	resource :companies do
      	  desc "Retrieve a list of Companies"
      	  get do
      	  	if params[:name]
      	  	  Company.where(name: params[:name])
      	  	else
      	  	  Company.all
      	  	end  
      	  end
      	end
      end
    end
  end
end  

We’ve setup an optional parameter, name which enables us to filter on our company. Ugly implementation aside, we’ve also been able to document as we go, and return all companies if no params were supplied. In addition to optional parameters, Grape also has options for required parameters with either custom, or inbuilt validations. For more fine grained validations, its even possible to validate on optional nested attributes if supplied, like so:


...
      params do
        requires :name, type: String, desc: 'Name of company'

        optional :contacts, type: Array, desc: 'List of contacts. Must be 1 or more.' do
          requires :first_name, type: String, desc: 'Contact First Name'
          requires :last_name, type: String, desc: 'Contact Last Name'
          optional :email_address, type: String, desc: 'Contact Email'
        end
      end


...

What if we’d like to control what data our end users get back though? Especially if we have some confidential information stored. Well, that’s where entities come in, grape comes with entity support and whilst you’re free to utilise RABL and ActiveModelSerializers, we’re going to be utilising the grape-entity gem.

Simply add grape-entity to your Gemfile, and let’s go ahead and create our first entity.


# /lib/controllers/api/v1/entities/company.rb

module AwesomeCompany
  module API
    module V1
      module Entities
        class Company < Grape::Entity
          expose :name, documentation: { type: 'String', desc: 'Company Name'}
          expose :address, documentation: { type: 'String', desc: 'Company Address'}
          expose :phone, documentation: { type: 'String', desc: 'Company Phone'}                  
        end
      end
    end
  end
end

We now wrap our data with a call to present and give it our entity object to ensure what we’re only sending back what we want to.


# /lib/controllers/api/v1/companies.rb

module AwesomeCompany
  module API
    module V1
      class Companies < Grape::API
      	params do
      	  optional :name, type: String, desc: 'Company name you wish to filter on'
      	end
      	resource :companies do
      	  desc "Retrieve a list of Companies"
      	  get do
      	  	companies = CompanyQuery.new(params)
      	  	present :company, companies, with: AwesomeCompany::API::V1::Entities::Company
          # -> { company: { name: 'Nigerian Royalty Incorporated', phone: '555-555', address: '55 Nigeria, Nigeria St, Nigeria' } }            
      	  	
      	  end
      	end
      end
    end
  end
end  

We’ve only really scratched the surface of what grape offers, their documentation is simply fantastic, so now that you have an API, have a dive into their README and see what else you can get up to