Grape Gemチュートリアル:RubyでRESTのようなAPIを構築する方法
公開: 2022-03-11Ruby On Rails開発者として、JavaScriptを多用するリッチインターネットクライアントまたはネイティブのiPhoneおよびAndroidアプリをサポートするために、APIエンドポイントを使用してアプリケーションを拡張する必要があることがよくあります。 アプリケーションの唯一の目的がJSONAPIを介してiPhone/Androidアプリを提供することである場合もあります。
このチュートリアルでは、Ruby用のRESTのようなAPIマイクロフレームワークであるGrapeを使用して、JSONAPI用のRailsでバックエンドサポートを構築する方法を示します。 Grapeは、Webアプリケーションに干渉することなく、Webアプリケーションを補完するマウント可能なラックエンジンとして実行するように設計されています。
使用事例
このチュートリアルで焦点を当てるユースケースは、ペアプログラミングセッションをキャプチャして確認できるアプリケーションです。 アプリケーション自体はObjectiveCでiOS用に作成され、データを保存および取得するためにバックエンドサービスと通信する必要があります。 このチュートリアルでは、JSONAPIをサポートする堅牢で安全なバックエンドサービスの作成に焦点を当てています。
APIは、次のメソッドをサポートします。
- システムにログインする
- ペアプログラミングセッションレビューのクエリ
注:ペアプログラミングセッションのレビューをクエリする機能を提供することに加えて、実際のAPIは、データベースに含めるためにペアプログラミングレビューを送信するための機能も提供する必要があります。 APIを介してそれをサポートすることはこのチュートリアルの範囲を超えているため、データベースにペアプログラミングレビューのサンプルセットが入力されていると単純に想定します。
主な技術要件は次のとおりです。
- すべてのAPI呼び出しは有効なJSONを返す必要があります
- 失敗したすべてのAPI呼び出しは、後で再現できるように適切なコンテキストと情報とともに記録し、必要に応じてデバッグする必要があります
また、アプリケーションは外部クライアントにサービスを提供する必要があるため、セキュリティに注意を払う必要があります。 その目的に向けて:
- 各リクエストは、追跡する開発者の小さなサブセットに制限する必要があります
- すべてのリクエスト(ログイン/サインアップを除く)は認証される必要があります
テスト駆動開発とRSpec
APIの決定論的な動作を保証するために、ソフトウェア開発アプローチとしてテスト駆動開発(TDD)を使用します。
テストの目的で、RubyOnRailsコミュニティでよく知られているテストフレームワークであるRSpecを使用します。 したがって、この記事では「テスト」ではなく「仕様」を参照します。
包括的なテスト方法は、「ポジティブ」テストと「ネガティブ」テストの両方で構成されます。 負の仕様は、たとえば、一部のパラメーターが欠落しているか正しくない場合にAPIエンドポイントがどのように動作するかを指定します。 ポジティブスペックは、APIが正しく呼び出される場合をカバーします。
入門
バックエンドAPIの基盤を築きましょう。 まず、新しいRailsアプリケーションを作成する必要があります。
rails new toptal_grape_blog
次に、 rspec-rails
をgemfileに追加してRSpecをインストールします。
group :development, :test do gem 'rspec-rails', '~> 3.2' end
次に、コマンドラインから次のコマンドを実行する必要があります。
rails generate rspec:install
また、テストフレームワークに既存のオープンソースソフトウェアを活用することもできます。 具体的には:
- Devise -Wardenに基づくRailsの柔軟な認証ソリューション
- factory_girl_rails -Rubyオブジェクトをテストデータとして設定するためのライブラリであるfactory_girlのRails統合を提供します
ステップ1:これらをgemfileに追加します。
... gem 'devise' ... group :development, :test do ... gem 'factory_girl_rails', '~> 4.5' ... end
ステップ2:ユーザーモデルを生成し、 devise
を初期化して、それをユーザーモデルに追加します(これにより、ユーザークラスを認証に使用できるようになります)。
rails g model user rails generate devise:install rails generate devise user
ステップ3:仕様でユーザー作成の短縮バージョンを使用するために、 rails_helper.rb
ファイルにfactory_girl
構文メソッドを含めます。
RSpec.configure do |config| config.include FactoryGirl::Syntax::Methods
ステップ4:ブドウの宝石をDSLに追加し、インストールします。
gem 'grape' bundle
ユーザーログインのユースケースと仕様
バックエンドは、基本的なログイン機能をサポートする必要があります。 有効なログイン要求が登録された電子メールアドレスとパスワードのペアで構成されていると仮定して、 login_spec
のスケルトンを作成しましょう。
require 'rails_helper' describe '/api/login' do context 'negative tests' do context 'missing params' do context 'password' do end context 'email' do end end context 'invalid params' do context 'incorrect password' do end context 'with a non-existent login' do end end end context 'positive tests' do context 'valid params' do end end end
いずれかのパラメータが欠落している場合、クライアントは「電子メールが欠落しています」または「パスワードが欠落しています」というエラーメッセージとともに、400のHTTPリターンステータスコード(つまり、不正な要求)を受け取る必要があります。
このテストでは、有効なユーザーを作成し、ユーザーの電子メールとパスワードをこのテストスイートの元のパラメーターとして設定します。 次に、パスワード/電子メールを省略するか、オーバーライドすることにより、特定の仕様ごとにこのパラメーターハッシュをカスタマイズします。
仕様の最初にユーザーとパラメーターのハッシュを作成しましょう。 このコードをdescribeブロックの後に配置します。
describe '/api/login' do let(:email) { user.email } let(:password) { user.password } let!(:user) { create :user } let(:original_params) { { email: email, password: password } } let(:params) { original_params } ...
次に、「欠落しているパラメータ」/「パスワード」コンテキストを次のように拡張できます。
let(:params) { original_params.except(:password) } it_behaves_like '400' it_behaves_like 'json result' it_behaves_like 'contains error msg', 'password is missing'
ただし、「email」と「password」のコンテキスト全体で期待値を繰り返す代わりに、期待値と同じ共有例を使用できます。 このために、 rails_helper.rb
ファイルでこの行のコメントを解除する必要があります。
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
次に、3つのRSpec共有例をspec/support/shared.rb
に追加する必要があります。
RSpec.shared_examples 'json result' do specify 'returns JSON' do api_call params expect { JSON.parse(response.body) }.not_to raise_error end end RSpec.shared_examples '400' do specify 'returns 400' do api_call params expect(response.status).to eq(400) end end RSpec.shared_examples 'contains error msg' do |msg| specify "error msg is #{msg}" do api_call params json = JSON.parse(response.body) expect(json['error_msg']).to eq(msg) end end
これらの共有例は、(DRYの原則に従って)仕様でAPIエンドポイントを1回だけ定義できるようにするapi_call
メソッドを呼び出しています。 このメソッドを次のように定義します。
describe '/api/login' do ... def api_call *params post "/api/login", *params end ...
また、ユーザー向けにファクトリをカスタマイズする必要があります。
FactoryGirl.define do factory :user do password "Passw0rd" password_confirmation { |u| u.password } sequence(:email) { |n| "test#{n}@example.com" } end end
そして最後に、仕様を実行する前に、移行を実行する必要があります。
rake db:migrate
ただし、APIエンドポイントをまだ実装していないため、この時点ではまだ仕様が失敗することに注意してください。 次です。
LoginAPIエンドポイントの実装
手始めに、ログインAPI( app/api/login.rb
)の空のスケルトンを記述します。
class Login < Grape::API format :json desc 'End-points for the Login' namespace :login do desc 'Login via email and password' params do requires :email, type: String, desc: 'email' requires :password, type: String, desc: 'password' end post do end end end
次に、APIエンドポイント( app/api/api.rb
)を集約するアグリゲータークラスを記述します。
class API < Grape::API prefix 'api' mount Login end
OK、これでAPIをルートにマウントできます。
Rails.application.routes.draw do ... mount API => '/' ... end
次に、不足しているパラメーターをチェックするコードを追加しましょう。 Grape::Exceptions::ValidationErrors
からレスキューすることで、そのコードをapi.rb
に追加できます。
rescue_from Grape::Exceptions::ValidationErrors do |e| rack_response({ status: e.status, error_msg: e.message, }.to_json, 400) end
無効なパスワードについては、http応答コードが不正アクセスを意味する401であるかどうかを確認します。 これを「不正なパスワード」コンテキストに追加しましょう。
let(:params) { original_params.merge(password: 'invalid') } it_behaves_like '401' it_behaves_like 'json result' it_behaves_like 'contains error msg', 'Bad Authentication Parameters'
次に、同じロジックが「ログインが存在しない」コンテキストにも追加されます。
次に、無効な認証の試行を処理するロジックを次のようにlogin.rb
に実装します。
post do user = User.find_by_email params[:email] if user.present? && user.valid_password?(params[:password]) else error_msg = 'Bad Authentication Parameters' error!({ 'error_msg' => error_msg }, 401) end end
この時点で、ログインAPIのすべてのネガティブな仕様は適切に動作しますが、ログインAPIのポジティブな仕様をサポートする必要があります。 私たちの肯定的な仕様では、エンドポイントが有効なJSONと有効なトークンを含む200のHTTP応答コード(つまり、成功)を返すことを期待しています。
it_behaves_like '200' it_behaves_like 'json result' specify 'returns the token as part of the response' do api_call params expect(JSON.parse(response.body)['token']).to be_present end
また、応答コード200の期待値をspec/support/shared.rb
に追加しましょう。
RSpec.shared_examples '200' do specify 'returns 200' do api_call params expect(response.status).to eq(200) end end
ログインに成功した場合、最初の有効なauthentication_tokenをユーザーの電子メールと一緒に次の形式で返します。
{'email':<the_email_of_the_user>, 'token':<the users first valid token>}
そのようなトークンがまだない場合は、現在のユーザー用にトークンを作成します。
... if user.present? && user.valid_password?(params[:password]) token = user.authentication_tokens.valid.first || AuthenticationToken.generate(user) status 200 else ...
これが機能するためには、ユーザーに属するAuthenticationToken
クラスが必要です。 このモデルを生成してから、対応する移行を実行します。
rails g model authentication_token token user:references expires_at:datetime rake db:migrate
また、対応する関連付けをユーザーモデルに追加する必要があります。
class User < ActiveRecord::Base has_many :authentication_tokens end
次に、 AuthenticationToken
クラスに有効なスコープを追加します。
class AuthenticationToken < ActiveRecord::Base belongs_to :user validates :token, presence: true scope :valid, -> { where{ (expires_at == nil) | (expires_at > Time.zone.now) } } end
where
ステートメントでRuby構文を使用したことに注意してください。 これは、activerecordクエリでRuby構文のサポートを可能にするsqueel
を使用することで可能になります。
検証済みのユーザーの場合、 grape-entity
の宝石の機能を活用して、「トークンエンティティを持つユーザー」と呼ばれるエンティティを作成します。
エンティティの仕様を記述して、 user_with_token_entity_spec.rb
ファイルに入れましょう。
require 'rails_helper' describe Entities::UserWithTokenEntity do describe 'fields' do subject(:subject) { Entities::UserWithTokenEntity } specify { expect(subject).to represent(:email)} let!(:token) { create :authentication_token } specify 'presents the first available token' do json = Entities::UserWithTokenEntity.new(token.user).as_json expect(json[:token]).to be_present end end end
次に、エンティティをuser_entity.rb
に追加しましょう。
module Entities class UserEntity < Grape::Entity expose :email end end
そして最後に、 user_with_token_entity.rb
に別のクラスを追加します。
module Entities class UserWithTokenEntity < UserEntity expose :token do |user, options| user.authentication_tokens.valid.first.token end end end
トークンが無期限に有効であり続けることを望まないため、トークンは1日後に期限切れになります。
FactoryGirl.define do factory :authentication_token do token "MyString" expires_at 1.day.from_now user end end
これで、新しく作成したUserWithTokenEntity
を使用して期待されるJSON形式を返すことができます。
... user = User.find_by_email params[:email] if user.present? && user.valid_password?(params[:password]) token = user.authentication_tokens.valid.first || AuthenticationToken.generate(user) status 200 present token.user, with: Entities::UserWithTokenEntity else ...
いいね。 これで、すべての仕様に合格し、基本的なログインAPIエンドポイントの機能要件がサポートされます。
ペアプログラミングセッションレビューAPIエンドポイント:はじめに
バックエンドでは、ログインした認定開発者がペアプログラミングセッションのレビューをクエリできるようにする必要があります。
新しいAPIエンドポイントは/api/pair_programming_session
にマウントされ、プロジェクトに属するレビューを返します。 この仕様の基本的なスケルトンを書くことから始めましょう:
require 'rails_helper' describe '/api' do describe '/pair_programming_session' do def api_call *params get '/api/pair_programming_sessions', *params end context 'invalid params' do end context 'valid params' do end end end
対応する空のAPIエンドポイント( app/api/pair_programming_sessions.rb
)も記述します。
class PairProgrammingSessions < Grape::API format :json desc 'End-points for the PairProgrammingSessions' namespace :pair_programming_sessions do desc 'Retrieve the pairprogramming sessions' params do requires :token, type: String, desc: 'email' end get do end end end
次に、新しいAPI( app/api/api.rb
)をマウントしましょう。
... mount Login mount PairProgrammingSessions end
要件に合わせて、仕様とAPIエンドポイントを1つずつ拡張してみましょう。
ペアプログラミングセッションレビューAPIエンドポイント:検証
最も重要な非機能セキュリティ要件の1つは、追跡する開発者の小さなサブセットにAPIアクセスを制限することだったので、次のように指定しましょう。
... def api_call *params get '/api/pair_programming_sessions', *params end let(:token) { create :authentication_token } let(:original_params) { { token: token.token} } let(:params) { original_params } it_behaves_like 'restricted for developers' context 'invalid params' do ...
次に、 shared_example
にshared.rb
を作成して、登録済みの開発者の1人からリクエストが送信されていることを確認します。
RSpec.shared_examples 'restricted for developers' do context 'without developer key' do specify 'should be an unauthorized call' do api_call params expect(response.status).to eq(401) end specify 'error code is 1001' do api_call params json = JSON.parse(response.body) expect(json['error_code']).to eq(ErrorCodes::DEVELOPER_KEY_MISSING) end end end
また、( app/models/error_codes.rb
に) ErrorCodes
クラスを作成する必要があります。

module ErrorCodes DEVELOPER_KEY_MISSING = 1001 end
APIは将来拡張されると予想されるため、アプリケーション内のすべてのAPIエンドポイントで再利用できるauthorization_helper
を実装して、登録済みの開発者のみにアクセスを制限します。
class PairProgrammingSessions < Grape::API helpers ApiHelpers::AuthenticationHelper before { restrict_access_to_developers }
ApiHelpers::AuthenticationHerlper
モジュール( app/api/api_helpers/authentication_helper.rb
)でメソッドrestrict_access_to_developers
を定義します。 このメソッドは、ヘッダーの下のキーAuthorization
に有効なApiKey
が含まれているかどうかを確認するだけです。 (APIへのアクセスを希望するすべての開発者は有効なApiKey
を必要とします。これはシステム管理者または自動登録プロセスを介して提供できますが、そのメカニズムはこの記事の範囲を超えています。)
module ApiHelpers module AuthenticationHelper def restrict_access_to_developers header_token = headers['Authorization'] key = ApiKey.where{ token == my{ header_token } } Rails.logger.info "API call: #{headers}\tWith params: #{params.inspect}" if ENV['DEBUG'] if key.blank? error_code = ErrorCodes::DEVELOPER_KEY_MISSING error_msg = 'please aquire a developer key' error!({ :error_msg => error_msg, :error_code => error_code }, 401) # LogAudit.new({env:env}).execute end end end end
次に、ApiKeyモデルを生成し、移行を実行する必要があります。rails g model api_key token rake db:migrate
これが完了すると、 spec/api/pair_programming_spec.rb
で、ユーザーが認証されているかどうかを確認できます。
... it_behaves_like 'restricted for developers' it_behaves_like 'unauthenticated' ...
また、すべての仕様( spec/support/shared.rb
)で再利用できるunauthenticated
されていない共有の例を定義しましょう。
RSpec.shared_examples 'unauthenticated' do context 'unauthenticated' do specify 'returns 401 without token' do api_call params.except(:token), developer_header expect(response.status).to eq(401) end specify 'returns JSON' do api_call params.except(:token), developer_header json = JSON.parse(response.body) end end end
この共有例では、開発者ヘッダーにトークンが必要なので、それを仕様( spec/api/pair_programming_spec.rb
)に追加しましょう。
... describe '/api' do let(:api_key) { create :api_key } let(:developer_header) { {'Authorization' => api_key.token} } ...
ここで、 app/api/pair_programming_session.rb
で、ユーザーの認証を試みましょう。
... class PairProgrammingSessions < Grape::API helpers ApiHelpers::AuthenticationHelper before { restrict_access_to_developers } before { authenticate! } ...
authenticate!
AuthenticationHelper
のメソッド( app/api/api_helpers/authentication_helper.rb
):
... module ApiHelpers module AuthenticationHelper TOKEN_PARAM_NAME = :token def token_value_from_request(token_param = TOKEN_PARAM_NAME) params[token_param] end def current_user token = AuthenticationToken.find_by_token(token_value_from_request) return nil unless token.present? @current_user ||= token.user end def signed_in? !!current_user end def authenticate! unless signed_in? AuditLog.create data: 'unauthenticated user access' error!({ :error_msg => "authentication_error", :error_code => ErrorCodes::BAD_AUTHENTICATION_PARAMS }, 401) end end ...
(エラーコードBAD_AUTHENTICATION_PARAMS
をErrorCodes
クラスに追加する必要があることに注意してください。)
次に、開発者が無効なトークンを使用してAPIを呼び出した場合に何が起こるかを特定しましょう。 その場合、戻りコードは「不正アクセス」を通知する401になります。 結果はJSONになり、監査可能なものが作成されます。 したがって、これをspec/api/pair_programming_spec.rb
に追加します:
... context 'invalid params' do context 'incorrect token' do let(:params) { original_params.merge(token: 'invalid') } it_behaves_like '401' it_behaves_like 'json result' it_behaves_like 'auditable created' it_behaves_like 'contains error msg', 'authentication_error' it_behaves_like 'contains error code', ErrorCodes::BAD_AUTHENTICATION_PARAMS end end ...
「auditablecreated」、「contains error code」、「containserrormsg」の共有例をspec/support/shared.rb
に追加します。
... RSpec.shared_examples 'contains error code' do |code| specify "error code is #{code}" do api_call params, developer_header json = JSON.parse(response.body) expect(json['error_code']).to eq(code) end end RSpec.shared_examples 'contains error msg' do |msg| specify "error msg is #{msg}" do api_call params, developer_header json = JSON.parse(response.body) expect(json['error_msg']).to eq(msg) end end RSpec.shared_examples 'auditable created' do specify 'creates an api call audit' do expect do api_call params, developer_header end.to change{ AuditLog.count }.by(1) end end ...
また、audit_logモデルを作成する必要があります。
rails g model audit_log backtrace data user:references rake db:migrate
ペアプログラミングセッションレビューAPIエンドポイント:結果を返す
認証および承認されたユーザーの場合、このAPIエンドポイントを呼び出すと、プロジェクトごとにグループ化されたペアプログラミングセッションレビューのセットが返されます。 それに応じてspec/api/pair_programming_spec.rb
を変更しましょう。
... context 'valid params' do it_behaves_like '200' it_behaves_like 'json result' end ...
これは、有効なapi_key
と有効なパラメーターを使用して送信されたリクエストが200のHTTPコード(つまり、成功)を返し、結果が有効なJSONの形式で返されることを指定します。
クエリを実行してから、参加者のいずれかが現在のユーザーであるペアプログラミングセッション( app/api/pair_programming_sessions.rb
)をJSON形式で返します。
... get do sessions = PairProgrammingSession.where{(host_user == my{current_user}) | (visitor_user == my{current_user})} sessions = sessions.includes(:project, :host_user, :visitor_user, reviews: [:code_samples, :user] ) present sessions, with: Entities::PairProgrammingSessionsEntity end ...
ペアプログラミングセッションは、データベースで次のようにモデル化されています。
- プロジェクトとペアプログラミングセッション間の1対多の関係
- ペアプログラミングセッションとレビューの間の1対多の関係
- レビューとコードサンプル間の1対多の関係
それに応じてモデルを生成してから、移行を実行してみましょう。
rails g model project name rails g model pair_programming_session project:references host_user:references visitor_user:references rails g model review pair_programming_session:references user:references comment rails g model code_sample review:references code:text rake db:migrate
次に、 has_many
アソシエーションを含むように、 PairProgrammingSession
クラスとReview
クラスを変更する必要があります。
class Review < ActiveRecord::Base belongs_to :pair_programming_session belongs_to :user has_many :code_samples end class PairProgrammingSession < ActiveRecord::Base belongs_to :project belongs_to :host_user, class_name: :User belongs_to :visitor_user, class_name: 'User' has_many :reviews end
注:通常の状況では、最初に仕様を記述してこれらのクラスを生成しますが、それはこの記事の範囲を超えているため、その手順はスキップします。
次に、モデルをJSON表現に変換するクラスを作成する必要があります(ブドウの用語ではブドウのエンティティと呼ばれます)。 簡単にするために、モデルとブドウの実体の間で1対1のマッピングを使用します。
まず、 CodeSampleEntity
( api/entities/code_sample_entity.rb
)からcode
フィールドを公開します。
module Entities class CodeSampleEntity < Grape::Entity expose :code end end
次に、定義済みのUserEntity
とCodeSampleEntity
を再利用して、 user
と関連するcode_samples
を公開します。
module Entities class ReviewEntity < Grape::Entity expose :user, using: UserEntity expose :code_samples, using: CodeSampleEntity end end
ProjectEntity
からname
フィールドも公開します。
module Entities class ProjectEntity < Grape::Entity expose :name end end
最後に、エンティティを新しいPairProgrammingSessionsEntity
にアセンブルし、 project
、 host_user
、 visitor_user
、およびreviews
を公開します。
module Entities class PairProgrammingSessionsEntity < Grape::Entity expose :project, using: ProjectEntity expose :host_user, using: UserEntity expose :visitor_user, using: UserEntity expose :reviews, using: ReviewEntity end end
これで、APIが完全に実装されました。
テストデータの生成
テストの目的で、 db/seeds.rb
にいくつかのサンプルデータを作成します。 このファイルには、データベースにデフォルト値をシードするために必要なすべてのレコード作成が含まれている必要があります。 次に、データをrake db:seed
でロードできます(または、 db:setup
が呼び出されたときにdbで作成されます)。 これに含まれる可能性のあるものの例を次に示します。
user_1 = User.create email: '[email protected]', password: 'password', password_confirmation: 'password' user_2 = User.create email: '[email protected]', password: 'password', password_confirmation: 'password' user_3 = User.create email: '[email protected]', password: 'password', password_confirmation: 'password' ApiKey.create token: '12345654321' project_1 = Project.create name: 'Time Sheets' project_2 = Project.create name: 'Toptal Blog' project_3 = Project.create name: 'Hobby Project' session_1 = PairProgrammingSession.create project: project_1, host_user: user_1, visitor_user: user_2 session_2 = PairProgrammingSession.create project: project_2, host_user: user_1, visitor_user: user_3 session_3 = PairProgrammingSession.create project: project_3, host_user: user_2, visitor_user: user_3 review_1 = session_1.reviews.create user: user_1, comment: 'Please DRY a bit your code' review_2 = session_1.reviews.create user: user_1, comment: 'Please DRY a bit your specs' review_3 = session_2.reviews.create user: user_1, comment: 'Please DRY your view templates' review_4 = session_2.reviews.create user: user_1, comment: 'Please clean your N+1 queries' review_1.code_samples.create code: 'Lorem Ipsum' review_1.code_samples.create code: 'Do not abuse the single responsibility principle' review_2.code_samples.create code: 'Use some shared examples' review_2.code_samples.create code: 'Use at the beginning of specs'
これでアプリケーションを使用する準備が整い、Railsサーバーを起動できるようになりました。
APIのテスト
Swaggerを使用して、APIの手動ブラウザーベースのテストを実行します。 ただし、Swaggerを使用できるようにするには、いくつかのセットアップ手順が必要です。
まず、gemfileにいくつかのgemを追加する必要があります。
... gem 'grape-swagger' gem 'grape-swagger-ui' ...
次に、 bundle
を実行して、これらのgemをインストールします。
また、これらをアセットパイプライン( config/initializers/assets.rb
)のアセットに追加する必要があります。
Rails.application.config.assets.precompile += %w( swagger_ui.js ) Rails.application.config.assets.precompile += %w( swagger_ui.css )
最後に、 app/api/api.rb
で、Swaggerジェネレーターをマウントする必要があります。
... add_swagger_documentation end ...
これで、Swaggerの優れたUIを利用して、 http://localhost:3000/api/swagger
にアクセスするだけでAPIを探索できます。
Swaggerは、APIエンドポイントをわかりやすく探索可能な方法で提供します。 エンドポイントをクリックすると、Swaggerはその操作を一覧表示します。 操作をクリックすると、Swaggerに必須およびオプションのパラメーターとそれらのデータ型が表示されます。
先に進む前に、残りの詳細が1つあります。有効なapi_key
を使用してAPI開発者の使用を制限したため、サーバーがHTTPヘッダーに有効なapi_key
を必要とするため、ブラウザーからAPIエンドポイントに直接アクセスすることはできません。 これは、GoogleChromeプラグインのヘッダーの変更を利用することでGoogleChromeでのテスト目的で実現できます。 このプラグインを使用すると、HTTPヘッダーを編集して、有効なapi_key
を追加できます(データベースシードファイルに含めた12345654321
のダミーapi_key
を使用します)。
OK、これでテストの準備が整いました。
pair_programming_sessions
APIエンドポイントを呼び出すには、最初にログインする必要があります。次に示すように、データベースシードファイルからの電子メールとパスワードの組み合わせを使用して、Swaggerを介してログインAPIエンドポイントに送信します。
上記のように、そのユーザーに属するトークンが返され、ログインAPIが意図したとおりに正しく機能していることを示します。 これで、そのトークンを使用して、 GET /api/pair_programming_sessions.json
操作を正常に実行できます。
示されているように、結果は適切にフォーマットされた階層JSONオブジェクトとして返されます。 プロジェクトには複数のレビューがあり、レビューには複数のコードサンプルがあるため、JSON構造は2つのネストされた1対多の関連付けを反映していることに注意してください。 この方法で構造を返さない場合、APIの呼び出し元は、プロジェクトごとに個別にレビューをリクエストする必要があり、APIエンドポイントにN個のクエリを送信する必要があります。 したがって、この構造を使用して、N+1クエリのパフォーマンスの問題を解決します。
要約
ここに示されているように、APIの包括的な仕様は、実装されたAPIが意図された(そして意図されていない!)ユースケースに適切かつ適切に対処することを保証するのに役立ちます。
このチュートリアルで紹介するAPIの例はかなり基本的なものですが、ここで示したアプローチと手法は、Grapegemを使用した任意の複雑さのより洗練されたAPIの基盤として役立ちます。 このチュートリアルは、GrapeがRailsアプリケーションでのJSONAPIの実装を容易にするのに役立つ便利で柔軟なgemであることを示していると思います。 楽しみ!