RESTful API の作成に特化したマイクロフレームワーク grape の存在を知ったので調査してみる事にしました。API の実装 に Rails の ActionController は重厚すぎる、Sinatra は軽いけど手間がかかる。。。という中で作られたこのフレームワーク、はたしてその実力は…

grape の特徴

grape の特徴は概ね以下の通りです。grape 自体が Rack アプリケーションなので Rails3 に組み込むことが出来ます。というよりは組み込んで使うのが前提のようです(勿論単体でも動きます)。

  • Rack アプリケーション
  • Sinatra ライクな DSL
  • 自動で JSON にシリアライズ(#serializable_hash または #to_json が存在すればOKみたい)

grape を使ってみる

特徴を掴んだところで、実際にインストールして使ってみます。Rails3 の一部として使う場合は Gemfile に下記1行を追加して、おなじみ bundle install を実行します。

gem "grape"

今回は lib/api.rb に実装していきます。実装したコードは下記をご覧下さい。prefix を指定すると /api/articles/1 という感じのURLになります。コメントアウトしてますが、version を指定すると /1/articles/1 のようにアクセス出来るようになるみたいです(これに何のメリットがあるのかはちょっと分かりませんでした)。

用意されている DSL の詳細は、intridea/grape – GitHubYARD documentation for the Grape API などを見て下さい。

# lib/api.rb
 
module TestApp
  class API < Grape::API
    # version 1
    prefix "api"
 
    resource "articles" do
      get ":id" do
        Article.find(params[:id])
      end
    end
  end
end

APIの実装が終わったら次はRailsへの組み込みです。Rails3 から lib の中は自動で読み込まれないので initializers で呼び出すようにします。

# config/initializers/api.rb
 
require "#{Rails.root/lib/api"

最後に TestApp::API を routes.rb でマウントして完成です。

# config/routes.rb
 
TestApp::Application.routes.draw do
  mount TestApp::API => "/"
end

ここまで出来たら rails s で WEBRick を起動し、http://localhost:3000/api/articles/1 にアクセスしてみましょう。Article.find(1) の実行結果が JSON で返ってくるはずです。

軽くベンチマークしてみた

試しに ActionController と grape どちらがパフォーマンス良いのかをベンチマークしてみました。

コントローラの実装は次のようにしました。

# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
  respond_to :json
 
  def show
    respond_with Article.find(params[:id])
  end
end
 
# config/routes.rb
TestApp::Application.routes.draw do
  resources :articles
end

Apache Bench で測定してみます。測定環境ですが、ローカルは自宅のiMac、リモートはさくらのVPS 4G(unicorn 使用)で行いました。ですのでベンチマーク結果はあくまで参考程度に考えてください。

grape

Concurrency Level:      10
Time taken for tests:   5.039 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      545000 bytes
HTML transferred:       345000 bytes
Requests per second:    198.47 [#/sec] (mean)
Time per request:       50.385 [ms] (mean)
Time per request:       5.039 [ms] (mean, across all concurrent requests)
Transfer rate:          105.63 [Kbytes/sec] received

ActionController

Concurrency Level:      10
Time taken for tests:   7.573 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      643000 bytes
HTML transferred:       355000 bytes
Requests per second:    132.05 [#/sec] (mean)
Time per request:       75.731 [ms] (mean)
Time per request:       7.573 [ms] (mean, across all concurrent requests)
Transfer rate:          82.92 [Kbytes/sec] received

grape のほうが少し速い結果となりました。何回かやってみたのですが、多少誤差はあるものの grape のほうが速そうです。

総評

Sinatra ライクな DSL なおかげでかなりシンプルに書けることが分かりました。ただ、Rails3 からは respond_with が使えるようになったので、コード量ではあまり差は無くなってしまいますね。通常のHTMLページとAPIを分離したい場合やパフォーマンスアップを狙いたい場合には良いかもしれません。

ロードマップを見ると、OAuth認証やXMLでの出力、Streaming APIの対応も予定されているようです。

関連リンク