Posted at

RailsでAPIを作成するために色々比較したので所感と実装方法のご紹介

More than 3 years have passed since last update.


はじめに

外部サービスと連携したい!アプリ開発をしたい!際に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に設定をします。


config/routes.rb

# API用

namespace :api, {format: 'json'} do
namespace :v1 do
namespace :users do
get "/" , :action => "index"
end
end
end


controllerの実装

controllerを実装していきます。

railsを書き慣れている人なら特に違和感はないかと思います。

params.permitにてリクエストパラメータのバリデーションをかけています。


app/controllers/api/v1/users_controller.rb

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のインストール


Gemfile.rb

gem 'grape'



インストール

bundle install



routesの設定


config/routes.rb

mount API::Root => '/api'



grapeを読み込めるように設定


config/application.rb

# 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を作成します。


apis/api/root.rb

module API

class Root < Grape::API
mount API::Ver1::Root
end
end

apis/api/ver1 配下にroot.rbを作成します。


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部分の実装


app/apis/api/ver1/user.rb

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)の部分をRailsRABLJbuilderを使った所感、実装方法をご紹介します。


Rails


所感


  • 簡単なものなら事足りるが、複雑なレスポンスは厳しそう。

  • controller内にレスポンスの処理が含まれるので、管理が疎かになりがち

って感じです。デモ等の簡単なものなら良いですが、複雑なものはちょっと厳しそうな印象です。


実装方法

先ほどリクエストの取得部分のRailsの項目で作成したコードを元にJSONして出力出来るようにします。


app/controllers/api/v1/users_controller.rb

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


Gemfile

gem 'rabl'



shell

bundle install



コードの修正

こちらもリクエストの取得部分のRailsの項目で作成したコードを元にJSONして出力出来るようにします。


app/controllers/api/v1/users_controller.rb

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のディレクトリ構造にする


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に比べると直感的で解りやすいと感じました。何よりモデルに紐付かない処理も表現しやすいのはかなり良いですね。


実装方法


Gemfile

gem 'grape'

gem 'grape-jbuilder'


shell

bundle install



API部分の修正

先ほどリクエストの取得部分のGrapeの項目で作成したコードを元にJSON出力出来るようにします。


app/apis/api/ver1/user.rb

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

が良さそうだと感じました。