CookpadさんがOSSで先日OSSで公開されたGarageはRestfulなAPI + OAuth(Doorkeeper)をワンストップで提供してくれるgemです。 ちょうど触る機会が出てきたので、今回四苦八苦しながら使ってみたのでそのメモです!
🎂 今回のサンプル実装
今回はOAuthで認証して、次のシンプルなAPIにアクセスできるようにするまでのサンプルを作成します。
GET /v1/users => ユーザーのリスト出力
GET /v1/users/:id => 個々のユーザー情報の出力
🎃 Gemの追加
Gemfile
に以下を追加して、bundle install
。
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の初期設定とか、マイグレーションとかを実行。
# 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の設定を記述。
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
にルーティングを追記。
Rails.application.routes.draw do use_doorkeeper scope :v1 do resources :users, only: %i(index show update) end end
🗽 コントローラの作成 app/controllers/application_controller.rb
に共通の設定を追記。
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
を作成して、設定を追記。
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
にモデルの設定を追記。
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
🎉 動作確認 # テストユーザーの作成 $ bundle exec rails runner 'User.create(name: "morizyun", email: "[email protected] ")' # サーバーの起動 $ bundle exec rails s
http://localhost:3000/oauth/applications
上のURLにアクセスして、テスト用のクライアントを登録します。 登録したら、APPLICTION_ID
とAPPLICATION_SECRET
を登録します。
# APPLICTION_IDとAPPLICATION_SECRETを使って、ACCESS_TOKENを取得 curl -u "$APPLICTION_ID:$APPLICATION_SECRET" -XPOST http://localhost:3000/oauth/token -d 'grant_type=password&[email protected] ' # 上で取得した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の設定。
# RSpecの初期設定 $ bundle exec rails g rspec:install
🐝 spec_helper.rbの設定 spec/spec_helper.rb
にFactoryGirl関連の設定を追加。
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
を作成して以下を追加。
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
で以下を追加。
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
を追加。
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
を以下のように変更。
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の実施 # 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
🐮 参考リンク RESTful Hypermedia APIをRailsで実現するcookpad/garageが凄い - Qiita
🖥 VULTRおすすめ
「VULTR 」はVPSサーバのサービスです。日本にリージョンがあり、最安は512MBで2.5ドル/月($0.004/時間)で借りることができます。4GBメモリでも月20ドルです。
最近はVULTR のヘビーユーザーになので、「ここ 」から会員登録してもらえるとサービス開発が捗ります!