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 に書くのに比べて可読性の高いコードが書けることがわかった。