CookpadさんがOSSで先日OSSで公開されたGarageはRestfulなAPI + Oauth(Doorkeeper)をワンストップで提供してくれるgemです。
ちょうど触る機会が出てきたので、今回四苦八苦しながら使ってみたのでそのメモです!
今回のサンプル実装
今回はOauthで認証して、以下のシンプルなAPIにアクセスできるようにするまでのサンプルを作成します。
GET /v1/users => ユーザーのリスト出力
GET /v1/users/:id => 個々のユーザー情報の出力
Gemの追加
Gemfile
に以下を追加して、bundle install
。
1
2
3
4
5
6
7
gem 'garage' , github : 'cookpad/garage'
gem 'responders' , '~> 2.0' # If you use Rails4.2+
group :development , :test do
gem 'factory_girl_rails' , '~> 4.5.0'
gem 'rspec-rails' , '~> 3.1.0'
end
DBの設定(Migration)
GagrageやRspecの初期設定とか、マイグレーションとかを実行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Doorkeeper(Oauth認証)の初期設定
$ bundle exec rails generate doorkeeper:install
# Doorkeeper(Oauth認証)のMigrationファイル生成
$ bundle exec rails generate doorkeeper:migration
# DBの作成
$ bundle exec rake db:create
# 認証用のユーザーモデル作成
$ bundle exec rails g model user name:string email:string
# マイグレーション処理の実行
$ bundle exec rake db:migrate
Garageの設定
config/initializers/garage.rb
を作成して、Garageの設定を記述。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Garage . configure {}
Garage :: TokenScope . configure do
register :public , desc : 'accessing publicly available data' do
access :read , User
access :write , User
end
end
Doorkeeper . configure do
orm :active_record
# デフォルトのスコープ
default_scopes :public
optional_scopes ( * Garage :: TokenScope . optional_scopes )
# アプリケーションのオーナーの認証
resource_owner_from_credentials do | routes |
User . find_by ( email : params [ :username ] )
end
end
ルーティングの設定
config/routes.rb
にルーティングを追記。
1
2
3
4
5
6
7
Rails . application . routes . draw do
use_doorkeeper
scope :v1 do
resources :users , only : % i ( index show update )
end
end
コントローラの作成
app/controllers/application_controller.rb
に共通の設定を追記。
1
2
3
4
5
6
7
8
class ApplicationController < ActionController :: Base
# ↓ 以下追記する内容
include Garage :: ControllerHelper
def current_resource_owner
@current_resource_owner ||= User . find ( resource_owner_id ) if resource_owner_id
end
end
app/controllers/users_controller.rb
を作成して、設定を追記。
1
2
3
4
5
6
7
8
9
10
11
12
13
class UsersController < ApplicationController
include Garage :: RestfulActions
# index
def require_resources
@resources = User . all
end
# show
def require_resource
@resources = User . find ( params [ :id ] )
end
end
モデルの設定
更にapp/models/user.rb
にモデルの設定を追記。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class User < ActiveRecord :: Base
include Garage :: Representer
include Garage :: Authorizable
property :id
property :name
property :email
# index
def self . build_permissions ( perms , other , target )
perms . permits! :read
end
# create/update/show/destory
def build_permissions ( perms , other )
perms . permits! :read
perms . permits! :write
end
end
動作確認
1
2
3
4
5
# テストユーザーの作成
$ bundle exec rails runner 'User.create(name: "morizyun", email: "morizyun@example.com")'
# サーバーの起動
$ bundle exec rails s
http://localhost:3000/oauth/applications
上のURLにアクセスして、テスト用のクライアントを登録します。
登録したら、APPLICTION_ID
とAPPLICATION_SECRET
を登録します。
1
2
3
4
5
6
7
8
# APPLICTION_IDとAPPLICATION_SECRETを使って、ACCESS_TOKENを取得
curl -u "$APPLICTION_ID:$APPLICATION_SECRET" -XPOST http://localhost:3000/oauth/token -d 'grant_type=password&username=morizyun@example.com'
# 上で取得したACCESS_TOKENを使ってAPIでuserの一覧を取得
curl -s -XGET -H "Authorization: Bearer $ACCESS_TOKEN" http://localhost:3000/v1/users | jq '.'
# 上で取得したaccess_tokenを使ってAPIでuserの一覧を取得
curl -s -XGET -H "Authorization: Bearer $ACCESS_TOKEN" http://localhost:3000/v1/users/1 | jq '.'
より複雑な処理のためにテストを書く
ここから更に複雑な処理を記述するために、RSpecでテストを記述できるようにします。
RSpecの設定
RSpecの設定。
1
2
# RSpecの初期設定
$ bundle exec rails g rspec:install
spec_helper.rbの設定
spec/spec_helper.rb
にFactoryGirl関連の設定を追加。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
require 'factory_girl_rails'
RSpec . configure do | config |
config . before :all do
FactoryGirl . reload
FactoryGirl . factories . clear
FactoryGirl . sequences . clear
FactoryGirl . find_definitions
end
config . include FactoryGirl :: Syntax :: Methods
config . expect_with :rspec do | expectations |
expectations . include_chain_clauses_in_custom_matcher_descriptions = true
end
end
request_helper.rbの設定
RSpec実行時にOauthの認証処理を予めやってくれて、access_tokenを取得してくれるhelperの作成。
spec/request_helper.rb
を作成して以下を追加。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
require 'active_support/concern'
module RequestHelper
extend ActiveSupport::Concern
included do
let ( :params) { {} }
let ( :report_status_env) do
{
accept: 'application/json' ,
authorization: report_status_authorization_header_value
}
end
let ( :report_status_authorization_header_value) { "Bearer #{report_status_access_token.token}" }
let ( :report_status_access_token) do
FactoryGirl.create(
:access_token,
resource_owner_id: resource_owner.id,
scopes: public,
application: application
)
end
let ( :resource_owner) { FactoryGirl.create( :user) }
let ( :report_status_scopes) { 'public' }
let ( :application) { FactoryGirl.create( :application) }
end
end
FactoryGirl(Fixture)の設定
spec/factories/users.rb
で以下を追加。
1
2
3
4
5
6
7
8
FactoryGirl . define do
factory :user do
name "MyString"
email "MyString"
sequence ( :name ) { | n | "user #{ n } " }
email { " #{ name } @example.com" }
end
end
Doorkeeper用の設定として、spec/factories/doorkeeper.rb
を追加。
1
2
3
4
5
6
7
8
9
10
11
12
FactoryGirl . define do
factory :access_token , class : Doorkeeper :: AccessToken do
sequence ( :resource_owner_id ) { | n | n }
application
expires_in 1 . hours
end
factory :application , class : Doorkeeper :: Application do
sequence ( :name ){ | n | "Application #{ n } " }
redirect_uri 'https://example.com/callback'
end
end
Specファイルの作成
spec/requests/users_spec.rb
を以下の様に変更。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require 'rspec_helper'
require 'request_helper'
RSpec . describe 'users' , type : :request do
include RequestHelper
describe 'GET /v1/users' do
let! ( :users ) { create_list ( :user , 3 ) }
it 'returns user resources' do
get '/v1/users' , params , env
expect ( response ) . to have_http_status ( 200 )
end
end
end
RSpecの実施
1
2
3
4
5
6
7
8
# Test環境用のDBの作成
$ RAILS_ENV = test bundle exec rake db:create migrate
# migrationの実施
$ RAILS_ENV = test bundle exec rake db:migrate
# users_specの実施
$ bundle exec rspec -fp spec/requests/users_spec.rb
ここから使いこなすのに参考になりそうな資料
CookpadさんのTech Blog の解説記事です。かなりわかりやすいですし、APIを作る時に参考になります^^
RESTful Web API 開発をささえる Garage - クックパッド開発者ブログ
Cookpadのエンジニアさんが作ってくれているサンプルのおかげでかなり捗りました!
taiki45/garage-example - GitHub
Special Thanks
RESTful Hypermedia APIをRailsで実現するcookpad/garageが凄い - Qiita