Why You Should Taste Grape

Hi folks, let's talk about APIs today.

I know that Rails 5 with --api mode is around the corner. But I need to say you how awesome is to build APIs with Grape. I will show you why.

What are the main features we expect from a good API?

  • Parameter validation
  • Parameter coercion
  • Documentation
  • Serialization
  • Performance
  • Versioning
  • Authentication
  • Testing

The first four items are the ones in which Grape really shines for me. I am going through one at a time.

Getting Started

For this tutorial, let's suppose we need to build an API to create and list customers.

require 'grape'

module MyAwesomeApi
class Customer < Grape::API
format :json

resource :customers do
post "/" do
Customer.create(params)
end

get ":id" do
{ customer: Customer.find(params[:id]) }
end
end
end
end

Ok, this is our starting point. Anyone used to Rails can grasp this snippet.

We have two routes, the first to create and the second to get customers.

Parameter validation

Something nice in Grape is that we can declare and validate the expected params in every route.

Parameter validation is as simple as telling Grape what we want. Given our base code above, we can simply add some validation by doing:

resource :customers do
params do
requires :first_name, type: String, regexp: /[A-z]+/
optional :last_name, type: String
requires :gender, values: %w(m f), default: "m"
requires :birthdate, type: Date, allow_blank: false
end
post "/" do
Customer.create(declared(params, include_missing: false))
end
end

declared(params, include_missing: false) returns only declared params which aren't missing (has some value).

If any validation fails, a 400 HTTP status code will be automatically returned with the error(s).

Parameter coercion

Sometimes we need to treat some param before using it. Look how easy it is:

resource :customers do
params do
# ...
requires :occupation, coerce_with: ->(obj) { obj.strip }
end
post "/" do
Customer.create(declared(params, include_missing: false))
end
end

Here we strip the occupation param.

Documentation

A good API must be well documented.

resource :customers do
desc "Creates a new customer",
http_codes: [
{ code: 201, message: "Created successfully" },
{ code: 400, message: "Invalid params" },
{ code: 401, message: "Not authorized" }
]
params do
# ...
requires :first_name, desc: "Customer's first name"
end
post "/" do
Customer.create(declared(params, include_missing: false))
end
end

We are able to document the response of each endpoint. Check grape-swagger to see what you can do with it.

Serialization

With grape-entity we can organize our serialization code and keep it dry:

# entities/customer.rb
module Entities
class Customer < Grape::Entity
expose :id
expose :first_name
expose :last_name
expose :avatar_url do |instance, _options|
instance.avatar.url
end
end
end
get ":id" do
customer = Customer.find(params[:id])
present customer, with: Entities::Customer
end

It will return only the specified attributes.

Ok, it seems nice, but..

I like Rails. Do I have to stop using it to use Grape?

No! You can mount a Grape API inside your Rails application (or Sinatra, Rack..).

Read Grape's readme and give it a try.

Enjoy yourself.

Written on April 14, 2016

Share: