Grapeをもう少し使ってみました。関連記事は↓

RailsのGrapeとJbuilderでAPI開発 - ぴよログ

基本形

1# app/api/api.rb
2resource :items do
3  get '/', jbuilder:'items' do
4    @items = Item.all
5  end
6end

パラメータを受け取る

全てのItemではなく、idに該当するItemだけが欲しいとき。

1resource :items do
2  get '/:id', jbuilder:'item' do
3    @item = Item.find_by_id(params[:id])
4  end
5end

/api/items/1というエンドポイントでid=1のItemが得られます。

ネストする

  • Item
  • Entry

というモデルがあって、Item has many Entriesな関連を持っている場合はリソースをネストさせることが多いと思います。Railsのルーティングとかでもよくやるアレです。Grapeでも似たような書き方ができます。

 1resource :items do
 2  route_param :item_id do
 3    resource :entries do
 4      get '/', jbuilder:'entries' do
 5        @item = Item.find_by_id(params[:item_id])
 6        @entries = @item.entries if @item
 7      end
 8
 9      get '/:id', jbuilder:'entry' do
10        @item = Item.find_by_id(params[:item_id])
11        @entry = @item.entries.find_by_id(params[:id]) if @item
12      end
13    end
14  end
15end

上のコードにより2つのAPIが定義されます。

  • /api/items/1/entriesでItem(id=1)のEntryを全て返す
  • /api/items/1/entries/1でItem(id=1)のEntryのうち(id=1)のものを返す

ネストの階層はこのようになっています。

  1. resource :items
  2. route_param :item_id
  3. resource :entries

2番めに出てくるroute_paramというのがありますが、実はこれresourceのエイリアスでGrapeの中では同じように扱われます。

公式ドキュメントによると元々はnamespaceというメソッドがあって、それに対するaliasとして以下のものが定義されているようです。

  • namespace
  • group
  • resource
  • resources
  • segment
  • route_param

読みやすくなるようコンテキストに応じて使えばよいということで、上のような場合はやはりresource(s)route_paramが適切っぽいでしょう。

API定義全体

 1class API < Grape::API
 2  format :json
 3  formatter :json, Grape::Formatter::Jbuilder
 4  default_format :json
 5
 6  resource :items do
 7    get '/', jbuilder:'items' do
 8      @items = Item.all
 9    end
10
11    params do
12      requires :id, type: Integer, desc: "Item ID"
13    end
14    get '/:id', jbuilder:'item' do
15      @item = Item.find_by_id(params[:id])
16    end
17
18    params do
19      requires :item_id, type: Integer, desc: "Item ID"
20    end
21    route_param :item_id do
22      resource :entries do
23        get '/', jbuilder:'entries' do
24          @item = Item.find_by_id(params[:item_id])
25          @entries = @item.entries if @item
26        end
27
28        params do
29          requires :id, type: Integer, desc: "Entry ID"
30        end
31        get '/:id', jbuilder:'entry' do
32          @item = Item.find_by_id(params[:item_id])
33          @entry = @item.entries.find_by_id(params[:id]) if @item
34        end
35      end
36    end
37  end
38
39end