ぴよログ

↓に移転したのでこっちは更新されません、多分。

RailsのGrapeとJbuilderでAPI開発

移転しました →

RailsAPIを作るならGrapeを使うってのが定番っぽいので使ってみました。

参考にしたのはこのへん

Grapeの導入〜Hello World

インストールはgem installすればOKです。次にAPIの実装コードを書くファイルを用意します。僕は#{Rails.root}/app/api/api.rbとしました。

# app/api/api.rb
class API < Grape::API
  format :json

  resource :items do
    get '/hello' do
      {hello: "world"}
    end
  end
end

そしてroutes.rbにてGrapeをマウントします。

# routes.rb
mount API => "/api"

APIは↑で定義したクラス名です。

以上のコードでhttp://domain.com/api/items/helloというURLに対するGETで{hello:"world"}というレスポンスが得られます。これが概要。

mountとプレフィックス

mount API => "/api"としましたがこれは自由に変更できます。mount API => "/"と、ルートを指定することができます。

この他にAPIクラスにprefixを付けることができるようになっていて、

class API < Grape::API
  format :json
  prefix "api" #この行
  
  # ...
end

↑のように書くとAPIクラスに定義されているAPIのURLにapiと付けられるようになります。

ところで、マウントパスとprefixの両方定義することができます。Grapeの使い始めで色々いじっていたときに両方に"api"という値を入れてしまい、/api/api/items/helloというURLでアクセスしなければならないことに気が付かず、/api/items/helloが404になってしまうことにしばらくハマりました。

JbuilderでViewを書く

さきほどのサンプルではレスポンスのjsonを直書きしましたが、プロダクションレベルではさすがにそんなことはしません。htmlのViewを作るときのように別ファイルを使って書きます。

Rails4にはjsonを作るためのjbuilderというgemがデフォルトで含まれるのでそれを使うと良いでしょう。他にはRablというものがあります。

GrapeでJbuilderを使うにはgrape-jbuilderというgemを導入します。

milkcocoa/grape-jbuilder

導入はGemfilegem 'grape-jbuilderでおk。

すると、Grape::Formatter::Jbuilderが使えるようになります。FormatterはAPIクラスで次のように指定することができます。

class API < Grape::API
  format :json
  formatter :json, Grape::Formatter::Jbuilder
end

あとはjbuilderを使うAPIにどのViewを対応させるかを書いてあげれば使えるようになります。

app/views/api/items.jbuilderファイルを使う場合、apiのほうにはjbuilder:'items'と書きます。

# app/api/api.rb
resource :items do
  get '/', jbuilder:'items' do
    @items = Item.all
  end
end

Viewのほうには、@itemsを使うようなコードを書くと動的にViewを生成できるようになるわけです。シンタックスは違えど、ERBと同じような感じです。

# app/views/api/items.jbuilder
json.items do
  json.array!(@items) do |item|
    json.(item, :id, :title, ..などなど..)
  end
end

例えばこのようなjsonが得られるわけですね。

{
    "items": [
        {
            "title": "hogehoge",
            "id": 1
        },
        {
            "title": "foobar",
            "id": 2
        }
    ]
}