逃げる8回で会心の一撃

Web エンジニアのサトウリョウスケが開発とか色々書くブログです

my_api_client v0.13.0 をリリースしました🚀

つい先日、v0.12.0 をリリースしたばかり ですが、 v0.13.0 をリリースしましたので、含まれる PR の内容について解説していきます。 より詳しい使い方は README.jp.md をご参照ください。

github.com

#180 Stub response on raising error (@ryz310)

今回はこの PR のみの更新です。 仕事で spec 書いてる最中に「API リクエストで例外が発生した際にレスポンス内容を保存する処理のスタブ化できないじゃん」ってなって作りました。

my_api_client では作成した API Client クラスを stub_api_client または stub_api_client_all というメソッドでスタブ化できます。 例えば以下のような ExampleApiClient というクラスを定義した時:

class ExampleApiClient < MyApiClient::Base
  endpoint 'https://example.com'

  error_handling status_code: 400..499, raise: MyApiClient::ClientError
  error_handling status_code: 500..599, raise: MyApiClient::ServerError

  # GET https://example.com/path/to/resouce
  def request
     get 'path/to/resouce'
  end
end

stub_api_client_all を実行すると ExampleApiClientインスタンスが全てスタブ化されるようになります。 以下の例だと、 #request を実行した時、API から { "message": "Hello world!" } という JSON が返ってきた時と同じ振る舞いをするようになります。

stub_api_client_all(
  ExampleApiClient,
  request: { response: { message: 'Hello world!' } }
)

api_client = ExampleApiClient.new
response = api_client.request
response.message # => 'Hello world!'

で、 error_handlingステータスコード400..499 の時は MyApiClient::ClientError という例外が発生する、という定義になっているのですが、このような例外が発生した時のテストを書くために、 raise のスタブ化も出来るようになっています。

stub_api_client_all(
  ExampleApiClient,
  request: { raise: MyApiClient::ClientError }
)

begin
  api_client = ExampleApiClient.new
  response = api_client.request
rescue MyApiClient::ClientError
  puts '4xx error!'
end

大抵の場合、これらのスタブ化ができれば問題ないのですが、例外発生時のレスポンスを見たい、というケースも無くはないかと思います。 仕様として、例外インスタンス#params#matadata というメソッドからリクエストパラメータとレスポンスパラメータを参照できるようになっています。

従来のスタブ化メソッドでも一応指定できなくはなかったんですが、結構手間だったので raise オプションの指定を以下のように拡張しました。 raise と一緒に指定した responseAPI のレスポンスとして返されて、それが例外として処理された、というスタブ化になります。

stub_api_client_all(
  ExampleApiClient,
  request: { 
    raise: MyApiClient::ClientError,
    response: { error_code: 10 }
  }
)

begin
  api_client = ExampleApiClient.new
  response = api_client.request
rescue MyApiClient::ClientError => e
  e.params.response.data.error_code #=> 10
end

my_api_client は内部で Sawyer を使っています。

github.com

e.params.responseSawyer::Response をそのまま返しているので、Sawyer::Response#data からレスポンスボディを参照できます。 Sawyer::Response#data では、レスポンスの JSONOpenStruct) のようにメソッドアクセスできるように変換してくれます。

ただし、 V1.0.0Sawyer の依存を無くしたいと考えているので、いずれ #data を挟む書き方は変更になるかもしれません。 一応こういう使い方もできますよ、という新機能でした。