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 – GitHub や YARD 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の対応も予定されているようです。