Grape::Entity の使い方

Grape で Web API 開発 - kzy52's blog

前回は Jbuilder を使いましたが 今回はGrape::Entityというgemを使ってJSONフォーマットを実装していきたいと思います。

ディレクトリ構成とルーティングは以下のようになる予定です。

├── app
│   ├── apis
│   │   ├── api
│   │   │   ├── base.rb
│   │   │   ├── v1
│   │   │   │   ├── base.rb
│   │   │   │   ├── comments.rb
│   │   │   │   └── message_boards.rb
│   │   │   └── v2
│   │   │       ├── base.rb
│   │   │       ├── comments.rb
│   │   │       └── message_boards.rb
│   │   └── entity
│   │       ├── v1
│   │       │   ├── comments_entity.rb
│   │       │   └── message_boards_entity.rb
│   │       └── v2
│   │           ├── comments_entity.rb
│   │           └── message_boards_entity.rb

Gem のインストール

# Gemfile

gem 'grape'
gem 'grape-entity'
$ bundle install

Entity の実装

# app/apis/entity/v1/message_boards_entity.rb

module Entity
  module V1
    class MessageBoardsEntity < Grape::Entity
      # {"message_boards":[]}
      # {"message_board":{} }
      # というJSON出力になります。
      root 'message_boards', 'message_board'

      expose :id, :title, :body
      # 値を加工することができる。
      expose :updated_at do |message_baord, options|
        message_baord.updated_at.strftime("%Y-%m-%d %H:%M:%S")
      end

      # 他のEntityの定義を使うことができる。
      expose :comments, using: 'Entity::V1::CommentsEntity'

      expose(:comment_count) do |message_board|
        message_board.comments.count(:id)
      end
    end
  end
end
# app/apis/entity/v1/comments_entity.rb

module Entity
  module V1
    class CommentsEntity < Grape::Entity
      # {"comments":[]}
      # というJSON出力になります。
      root 'comments'

      expose :id, :body, :updated_at
    end
  end
end

Entity を APIで指定する

# app/apis/api/v1/message_boards.rb

module API
  module V1
    class MessageBoards < Grape::API
      resource :message_boards do
        desc 'GET /api/v1/message_boards'
        get '/' do
          @message_boards = MessageBoard.all
          # 定義したエンティティはAPI側で指定する。
          present @message_boards, with: Entity::V1::MessageBoardsEntity
        end
        ...
        desc 'GET /api/v1/message_boards/:id'
        params do
          use :id
        end
        get '/:id' do
          set_message_board
          present @message_board, with: Entity::V1::MessageBoardsEntity
        end
        ...
    end
  end
end
module API
  module V1
    class Comments < Grape::API
      resource :message_boards do
        params do
          use :message_board_id
        end

        route_param :message_board_id do
          resource :comments do
            desc 'GET /api/v1/message_boards/:message_board_id/comments'
            get '/' do
              set_message_board
              @comments = @message_board.comments
              present @comments, with: Entity::V1::CommentsEntity
            end
            ...
    end
  end
end

Jbuilderより書きやすくていいですね。
ただEntityクラスをどこに配置するか悩ましいですね。
今回はディレクトリを切ってバージョニングしているのでこの方法にしてみました。

今回作ったもの

kzy52/grape-entity-example · GitHub