小さなエンドウ豆

まだまだいろいろ勉強中

Grape + Grape Entity で作る API

Grape + Grape Entity で作る API

Grape をよく使うので基本的な使い方から開発方法などを記す。 あと思いの外 Grape Entity が便利なので小技などをまとめておきたい。

Grape とは

github.com

Rails で RESTful な API を開発するためのフレームワーク。 Rails5 から提供された API モードで普通の Controller で簡単に開発することは可能になったが、 Grape の場合 REST に特化した DSL のためコードが追いやすい。

また Grape Entity と組み合わせることによってエンドポイント特有の結果を提供することが用意になる。

個人的にはコードが簡潔に保てるところが一番の強みだと思っている。

導入方法

「Grape 導入」で調べるといっぱい出てくるので割愛したい。 個人的に気にっているフォルダ構成は以下だ。

├── api
│   ├── base
│   │   └── api.rb
│   └── v1
│       ├── entities
│       │   ├── group_entity.rb
│       │   ├── idol_entity.rb
│       │   └── song_entity.rb
│       ├── groups.rb
│       ├── idols.rb
│       ├── root.rb
│       └── songs.rb

まず Rails プロジェクトの app 配下に api ディレクトリを作る。 そこに base と v1 というディレクトリを作る。 v1 ディレクトリはいわゆる API のバージョニングのためのもの。

api/base/api.rb と routes.rb にはそれぞれ以下が記述されているものとする。

# api/base/api.rb
module Base
  class API < Grape::API
    mount V1::Root
  end
end

# routes.rb
mount Base::API => '/'

こうすることによって API へのリクエストはすべて base/api.rb に流れる。 base の方の記述を見ると v1 に受け流している。 こうすることによって API のバージョンニングを用意にしている(のだと思う)。

v1 配下は Grape を記述していくところで entity ディレクトリは Grape Entity を記述するところである。

それでは Grape の構文を見ていく。

シンタックス

Grape

module V1
  class Idols < Grape::API
    resources :idols do
    desc 'return all idol'
    get '/' do
          @idols = Idol.all
      present @idols, with: V1::Entities::IdolEntity
        end
     end

    desc 'Create an idol'
    params do
      requires :name, type: String
      requires :group_id, type: Integer
    end
    post do
      @idol = Idol.new(name: params[:name], group_id: params[:group_id])
      if @idol.save
        status 201
        present @idol, with: V1::Entities::IdolEntity
      else
        status 400
        present @idol.errors
    end

     route_param :id do
       desc 'returns an idol'
         get do
           @idol = Idol.find(params[:id])
           present @idol, with: V1::Entities::IdolEntity
         end
       end
     end
  end
end

見ただけでどこに何が書いてあるかがわかりやすいと思います。 基本構文は以下のような感じです。

resource :{操作を加えるリソース名(モデル名)do
  desc '説明'
  paras do
    # パラメータを記述
  end
  {HTTP のメソッド} do
    # 処理
  end
end

このように記述することによって以下の操作が可能。

- GET: /idols ... 一覧の取得
- GET: /idols/1 ... 1件取得
- POST: /idols ... 作成

リソースの中にリソースをネストさせることも可能。

resource :groups do
  ... 
  resource :idols do
     ...
  end
end

この場合 idols には /groups/idols という URI でアクセスすることができる。

Grape Entity

上の例にも出てきているが present @idol, with: V1::Entities::IdolEntity の IdolEntity がそれである。 このファイルは以下のように記されている。

module V1
  module Entities
    class IdolEntity < Grape::Entity
      expose :id
      expose :name
      expose :group, using: V1::Entities::GroupEntity
    end
  end
end

expose に指定したフィールドをオブジェクトに問い合わせてその値を返してくれる。 この場合以下のような JSON オブジェクトが返ってくる。

{
  id: 1,
  name: "test",
  group: {
    id: 1,
   name: "test"
  }
}

ここでネストをさせているが Idol モデル belongs_to で Group に紐づくとする。 その場合紐づく group をたどって指定した GroupEntity に当てはめてくれる。

またモデルクラスに定義されているメソッドを返すこともできる。 例えば以下のような例が挙げられる。

module V1
  module Entities
    class IdolEntity < Grape::Entity
      expose :id
      expose :name do |idol|
        idol.full_name
      end
      expose :group, using: V1::Entities::GroupEntity
    end
  end
end

Idol クラスに full_name というメソッドが定義されているとする。 上のように expose :name にブロックを渡してあげることにより full_name の値を name として返すことができる。

まとめ

Grape を使って開発すると Controller に書くのに比べて可読性の高いコードが書けることがわかった。