はじめに
外部サービスと連携したい!アプリ開発をしたい!際にAPIサーバを作成することがあるかと思います。
今回はrubyを使った色々なAPIの実装方法をご紹介したいと思います。
登場人物
今回は下記の所感、実装方法をご紹介していきます。
リクエスト取得部分
- Rails
- Grape
レスポンス部分
- Rails
- RABL
- Jbuilder
前提
今回は全ての検証で下記のテーブル、URL、出力になるようになっています。
Userテーブルの構成
id | name | addr1 | addr2 |
---|---|---|---|
1 | 田中 | 東京都千代田区 | 0-0-0 |
2 | 山田 | 東京都千代田区 | 1-1-1 |
リクエストURL
今回はバージョン管理出来るようにapi/v1/
としました。
http://example.com/api/v1/users?addr1=東京都千代田区
レスポンス
[
{
id: 1,
name: "田中",
address: {
addr1: "東京都千代田区",
addr2: "0-0-0"
}
},
{
id: 2,
name: "山田"
address: {
addr1: "東京都千代田区",
addr2: "1-1-1"
}
},
]
リクエストの取得部分
Rails
所感
- Railsの規則通りなのでRailsに慣れている人なら敷居が低い
- Gemのインストール・設定が特にない
って感じですかね。試しにサクッとAPIを作るには向いていると思いました。
実装方法
controller配下にAPI用のディレクトリを作成する
ルーティングの設定
通常のRailsと同様にroutesに設定をします。
# API用
namespace :api, {format: 'json'} do
namespace :v1 do
namespace :users do
get "/" , :action => "index"
end
end
end
controllerの実装
controllerを実装していきます。
railsを書き慣れている人なら特に違和感はないかと思います。
params.permitにてリクエストパラメータのバリデーションをかけています。
class Api::V1::UsersController < ApplicationController
def index
@users = User.where("addr1 = ?", user_params[:addr1])
end
private
# リクエストパラメータのバリデーション
def user_params
params.permit(:addr1)
end
end
※ JSONとして出力する部分はレスポンス部分にて解説します。
grape
grapeとは
- rubyで簡単にAPIを作成するためのDSL
- 単体、もしくはRailsやSinatraと組み合わせ使う
所感
- API専用のDSLなのでシンプルにかける
- 若干初期設定が多い
って感じです。Railsに比べると大きめのプロジェクトに向いているのかなと感じました。
実装方法
Gemのインストール
gem 'grape'
bundle install
####routesの設定
mount API::Root => '/api'
grapeを読み込めるように設定
# APIの読み込み
config.paths.add File.join('app', 'apis'), glob: File.join('**', '*.rb')
config.autoload_paths += Dir[Rails.root.join('app', 'apis', '*')]
# Grape+JBuilderを使うための設定
config.middleware.use(Rack::Config) do |env|
env['api.tilt.root'] = Rails.root.join 'app', 'views', 'api'
end
ディレクトリの作成
grapeの場合は、app配下に下記図のように作成しました。
rootの設定
apis/api
配下にroot.rb
を作成します。
module API
class Root < Grape::API
mount API::Ver1::Root
end
end
apis/api/ver1
配下にroot.rb
を作成します。
module API
module Ver1
class Root < Grape::API
# これでdomain/api/v1でアクセス出来るようになる。
version 'v1', using: :path
format :json
mount API::Ver1::Users
# 404NotFoundの扱い
route :any, '*path' do
error! I18n.t('grape.errors.not_found'), 404
end
end
end
end
API部分の実装
module API
module Ver1
class Users < Grape::API
format :json
# /api/v1/users/
get '/users' do
@users = User.where("addr1 = ?", user_params[:addr1])
end
end
end
end
※ JSONとして出力する部分はレスポンス部分にて解説します。
レスポンス部分
続いてレスポンス(View)の部分をRails、RABL、Jbuilderを使った所感、実装方法をご紹介します。
Rails
所感
- 簡単なものなら事足りるが、複雑なレスポンスは厳しそう。
- controller内にレスポンスの処理が含まれるので、管理が疎かになりがち
って感じです。デモ等の簡単なものなら良いですが、複雑なものはちょっと厳しそうな印象です。
実装方法
先ほどリクエストの取得部分のRailsの項目で作成したコードを元にJSONして出力出来るようにします。
class Api::V1::UsersController < ApplicationController
def index
@users = User.where("addr1 = ?", user_params[:addr1])
@users = @users.map do |user|
{
id: user.id,
name: user.name,
address:{
addr1: user.addr1,
addr2: user.addr2
},
}
end
render json: @users
end
private
# リクエストパラメータのバリデーション
def user_params
params.permit(:addr1)
end
end
RABL
RABLの特徴
- Viewのテンプレートなのでcontrollerに記述しなくても良くなる
- JSON以外のフォーマットにも対応している
- API出力は基本的にモデルに紐づく
- 他のRails、Jbuilderに比べて若干遅い
所感
- 記述が独特なので慣れるまで少し時間がかかる
- 特定のモデルに紐づくプロパティを表すのには便利そう
って感じです。モデルに紐づく出力はRABLがかなりサポートしてくれるが、紐付かないモノを複雑に表現するには苦手そう。
また、記述が独特なので、そこは慣れが必要そうです。
実装方法
bundle install
gem 'rabl'
bundle install
コードの修正
こちらもリクエストの取得部分のRailsの項目で作成したコードを元にJSONして出力出来るようにします。
class Api::V1::UsersController < ApplicationController
def index
@users = User.where("addr1 = ?", user_params[:addr1])
render "api/ver1/users"
end
private
def user_params
params.permit(:addr1)
end
end
RABLファイルを格納するディレクトリの作成
app/views/api/ver1/users.json.rabl
のディレクトリ構造にする
collection @users, :object_root => false
attribute :id => :id, :name => :name
node (:address) do |user|
{
addr1: user.addr1,
addr2: user.addr2
}
end
Jbuilder
Jbuilderの特徴
- Viewのテンプレートなのでcontrollerに記述しなくても良くなる
- 記述方法がシンプルで解りやすい
- モデルに紐づかなくても簡単に扱える
所感
- 複雑なフォーマットも表現しやすい
- 条件式、モデルに紐付かないオブジェクトも簡単に扱えるので取り回しやすい
って感じです。RABLに比べると直感的で解りやすいと感じました。何よりモデルに紐付かない処理も表現しやすいのはかなり良いですね。
実装方法
gem 'grape'
gem 'grape-jbuilder'
bundle install
API部分の修正
先ほどリクエストの取得部分のGrapeの項目で作成したコードを元にJSON出力出来るようにします。
module API
module Ver1
class Users < Grape::API
format :json
formatter :json, Grape::Formatter::Jbuilder
# /api/v1/users/
get '/users', jbuilder: 'ver1/users/user' do
@users = User.where("addr1 = ?", user_params[:addr1])
end
end
end
end
View部分をJbuilderで実装
json.array! @users do |user|
json.id user.id
json.name user.name
json.address {
json.addr1 user.addr1
json.addr2 user.addr2
}
end
終わりに
API一つ作成するのでもかなり選択しがありました。
個人的に、簡単なAPIなら Rails単体、少し大きめのものならGreap + Jbuilder
が良さそうだと感じました。