【リクエストスペック①】APIの取得
はじめに
こんにちは!大ちゃんの駆け出し技術ブログです。
今回はタイトルにもある通り、リクエストスペックについて書きたいと思います。
しかし、リクエストスペックを説明するためにはAPIの説明が必要不可欠となるため、今回はAPI情報の取得方法、次回はAPI情報が取得できているかをテストするリクエストスペックという感じで2回構成で説明していきたいと思います!
他のテストタイプとの違い
「リクエストスペックってなんぞや?」
自分も最初はこんな感じでした。
自分がRSpecを学習する上で1番最初に学習したのはそのモデルをテストするモデルスペックです。主にテストの検証内容はそのモデルのバリデーションが効いているのかをテストすることです。
例: タスクモデルのモデルスペック
# spec/models/task_spec.rb require 'rails_helper' RSpec.describe Task, type: :model do describe 'validation' do it 'is valid with all attributes' do task = build(:task) expect(task).to be_valid expect(task.errors).to be_empty end it 'is invalid without title' do task_without_title = build(:task, title: nil) expect(task_without_title).to be_invalid expect(task_without_title.errors[:title]).to eq ["can't be blank"] end end end
次に学習した内容はシステムスペックでした。主にこちらのテストは自分の期待通りに画面が遷移し対象の要素が画面に表示されているのか、実装した機能が正しく動くかを検証します。圧倒的にこちらのテストを書く機会が多いですね。
例: ログイン機能のシステムスペック
require 'rails_helper' RSpec.describe 'UserSessions', type: :system do let(:user) { create(:user) } describe 'before login' do before { visit login_path } context 'when input values in the form are all valid' do before do fill_in 'Email', with: user.email fill_in 'Password', with: 'password' click_button 'Login' end it 'login successfully' do expect(page).to have_content 'Login successful' expect(current_path).to eq root_path end end end end
これら2つのテストは何度も書いたことがありました。しかし、新たに今回リクエストスペックという言葉が出てきました。これは一体何のテストなんでしょうか。
ある記事を参照すると、リクエストスペックはどうやら以下のようなテストがリクエストスペックと言えるそうです。
リクエストスペックとはシステムスペックと同じ統合テストにあたるようです。統合テストとは、モデルスペックのように個々に対して対してテストするのではなく、システムスペックのように集合的にテストする形式です。しかし、その以外はAPI系のテストの有無にあります。
「APIってなんぞや?」
みたいになるかと思いますが、詳しく説明すると大変ボリューミーになるので、詳しく知りたい方は他記事をあたってみてください。簡単に引用して説明すると下記のようなものがAPIです。
APIを、簡単に説明すると「決まった方法でアクセスをすれば決まった結果を返してくれるもの」です。先のケーススタディでいうと、URLの末尾にzipcode=郵便番号でアクセスすると、住所を決まった形式で返してくれるのです。一般的にはJSONという形式で結果が返ります。郵便番号の例もJSON形式です。どこからでもアクセスできる口を開けておき、決まった形式でアクセスを受け付けて、仕様通りの結果を返すインターフェースとなるのがAPIです。
よくTwitterAPIだったり、ぐるなびAPIだったりとAPIという単語自体は聞いたことはあるという人も多いのではないでしょうか。APIとはまさにそれらアプリが公開している情報のことであることを示しています。そして、その情報にアクセスすると一般的にはJSONの形式で返すようですね。例えば、下記の情報をぐるなびAPIが公開しているお店の情報に見立てることもできます。いろいろな情報がこちらで調べることなくJSON形式で手に入ります。
API情報の公開とは
自分が使用しているアプリを例にどのようにAPI情報へアクセスするか試してみましょう。
sorceryのログイン機能に関してアプリ内で行っているのはログインユーザーのAPI情報の公開です。詳しくみてみると下記のような状態です。
# app/controllers/api/v1/authentication_controller.rb module Api module V1 class AuthenticationController < BaseController def create @user = login(params[:email], params[:password]) raise ActiveRecord::RecordNotFound unless @user json_string = UserSerializer.new(@user).serialized_json render json: json_string end end end end
何かいつものログイン機能のファイルとは違いますね。。。
いつものsorceryのログイン機能のファイルは以下のような感じかと思います。
def create @user = login(params[:email], params[:password]) if @user redirect_back_or_to root_path else render :new end end
共通部分は下記の部分のみです。
@user = login(params[:email], params[:password])
なぜ今回使うファイルがいつものsorceryのログイン機能のファイルとは違うのかというと、今回テストするファイルはログインユーザーのAPI情報を返す仕様になっているからです。ここはかなりややこしいですね。
言い直すのならば、いつもsorceryでログイン機能を実装しているcreateアクションは、アプリ内でログインするための機能です。しかし、今回テストするcreateアクションはログインしたユーザーのデータをJSON形式で外部に公開する機能です。いつものsorceryのcreateアクションとは違い、API情報を公開する機能を持っているということです。
具体的にJSON形式で公開する方法を説明します。
まず、共通部分では同じように登録されているユーザーを取得します。
@user = login(params[:email], params[:password])
もし、ユーザーがいないのであれば例外を発生させます。
raise ActiveRecord::RecordNotFound unless @user
次の箇所は少し歪に見えるかと思います。
json_string = UserSerializer.new(@user).serialized_json
これはfast_jsonapi
のgemで生成したUserSerializer
を用いて、取得したユーザー情報をJSON形式に変更しています。json_string
の中身を見てみると、user情報がJSON形式で格納されているのがわかります。
5: def create 6: @user = login(params[:email], params[:password]) 7: raise ActiveRecord::RecordNotFound unless @user 8: json_string = UserSerializer.new(@user).serialized_json 9: 10: binding.pry 11: 12: render json: json_string 13: end [1] pry(#<Api::V1::AuthenticationController>)> json_string => "{\"data\":{\"id\":\"1\",\"type\":\"user\",\"attributes\":{\"name\":\"MyString1\",\"email\":\"MyText1\"}}}"
render json: json_string
このレンダリングを行うことで、ユーザー情報を外部からのアクセスで表示させることができるのです。
API情報へのアクセス方法
実際にアクセスして指定のユーザー情報を取得してみましょう。
このAPI情報をどのように取得するのかというと、上述したようにJSON形式のデータを取得するためには決まった形式のアクセスが必要です。今回のログインユーザーの情報にアクセスするためには、ルーティングを見るとわかります。
$ rails routes
api_v1_authentication POST /api/v1/authentication(.:format) api/v1/authentication#create {:format=>/json/}
Post形式で/api/v1/authenticationにアクセスする必要があるようです。
実際に指定のブラウザ上でも試せますが、Postmanというアプリを使うとAPI情報へのアクセスがわかりやすくなるので、Postmanを使います。
Post形式で/api/v1/authenticationを指定した画面が下記になります。
しかし、このままではアクセスできません。今回はログイン機能ですので、アプリで登録されているユーザーの指定のパラメーター情報を/api/v1/authenticationに加える必要があります。
@user = login(params[:email], params[:password])
Postamanで送る方法はとても簡単で、Query Paramsという項目に登録されてるユーザー情報に合致するパラメータを記載します。取得パラメーターはemail
とpassword
です。
するとURIの部分が自動で切り替わりました。
localhost:3000/api/v1/authentication?email=MyText1&password=password
これで指定のパラメーターを送ることが可能になったので、実際に送信ボタン(Send)を押してみましょう。するとJSON形式のデータが取得できたはずです。
{ "data": { "id": "1", "type": "user", "attributes": { "name": "MyString1", "email": "MyText1" } } }
ちなみにここで間違ったパラメーター渡してみると、ユーザー情報が取得できなかったために、raise ActiveRecord::RecordNotFound
の例外処理が実行され、下記のエラーメッセージのデータがJSON形式で表示されます。エラーハンドリングされているということですね。
{ "message": "Record Not Found", "errors": [ "ActiveRecord::RecordNotFound" ] }
終わりに
上述したように今回はあくまでAPIの概要や取得方法についての説明であり、本当に説明したのは次回説明するリクエストスペックについてです。今回のようにJSON形式のファイルが表示されているのかをテストする方法について発信していきますのでお楽しみに!
以上、大ちゃんの駆け出し技術ブログでした!