my_api_client v0.16.0 をリリースしました🚀
前回のリリースから 1 週間ほどですが、今日予定していたライブがコロナウイルスの影響で中止になったので暇を持て余しました 😷
v0.16.0 の新機能
2 つありますが、どちらも若干の Breaking Change です。 とはいえ普通に使っていたら全く影響を受けないと思います。
新機能 1. エラーハンドラがエラーを検出した際は常に例外を raise するようになりました
my_api_client
では JSON API からのレスポンス内容に応じて例外を発生させる error_handling
というメソッドが利用できます。
以下に error_handling
を利用した例を示します。
class ExampleApiClient < ApplicationApiClient endpoint 'https://example.com' error_handling json: { '$.errors.code': 10 } error_handling json: { '$.errors.code': 20 }, raise: MyErrorClass error_handling json: { '$.errors.code': 30 }, with: :my_error_handling error_handling json: { '$.errors.code': 40 } do |params, logger| # Do something. end # GET error/:code def request get 'path/to/resouce' end private def my_error_handling(params, logger) # Do something. end end
この例の場合、 ExampleApiClient#request
を実行すると GET https://example.com/path/to/resouce
に対してリクエストが実行され、レスポンスボディが JSON 形式だった場合、JSONPath $.error.code
の値に応じて以下の処理を実行します。
10
だった場合MyApiClient::Error
を発生させる20
だった場合MyErrorClass
を発生させる30
だった場合#my_error_handling
を実行する (例外は発生しない)40
だった場合do ~ end
を実行する (例外は発生しない)
MyApiClient::Error
は raise
オプションで例外クラスを指定しなかった場合のデフォルトの例外クラスです。
この時、従来は 30
と 40
のように with
や block
を利用した場合は、処理の中で明示的に raise
を実行しない限り、例外は発生しませんでした。
エラー検出時に例外を発生させるかどうかは、 my_api_client
の利用者に委ねられていた形になります。
しかしながら、ここに自由度を持たせるよりも、 エラー検出時には必ず raise
させて rescue
で異常時の処理を記述する 、という方式に統一した方が my_api_client
の利用方法としても理解しやすく、特に困るケースも想定されなかったことから、以下のように変更することにしました。
10
だった場合MyApiClient::Error
を発生させる (変更なし)20
だった場合MyErrorClass
を発生させる (変更なし)30
だった場合#my_error_handling
を実行し、MyApiClient::Error
を発生させる40
だった場合do ~ end
を実行し、MyApiClient::Error
を発生させる
今後はエラー検出時には常に何らかの例外が raise
されるようになります。
上記の例では MyApiClient::Error
が発生しますが、 with
や block
と同時に raise
を指定すれば、任意の例外クラスが発生するようになります。
これにより、 with
や block
は例外の前処理という位置付けになります。ユースケースとしてはログ出力や slack への通知などが考えられます。
新機能 2. 標準のエラーハンドラが用意されました
my_api_client
では generator 機能 が用意されており、 $ rails g api_client path/to/resource get:path/to/resource
を実行すると以下のファイルが作成されます。
create app/api_clients/application_api_client.rb create app/api_clients/path/to/resource_api_client.rb invoke rspec create spec/api_clients/path/to/resource_api_client_spec.rb`
この時、 application_api_client.rb
に標準のエラーハンドラの例がいくつか記載されるのですが、例というより必須のエラーハンドラだよね、ということで、 my_api_client
の内部で標準実装するようにしました。
これにより、ステータスコード 4xx と 5xx のレスポンスに対しては標準で例外が発生するようなります。また、ネットワーク系のエラーに対しても標準で 300 msec
間隔を空けて 3 回リトライが試行されるようになります。(リトライ処理も従来は明示的な定義が必須でした)
# 従来の `application_api_client.rb` に出力されていた標準のエラーハンドラ例 error_handling status_code: 400..499, raise: MyApiClient::ClientError error_handling status_code: 500..599, raise: MyApiClient::ServerError # 従来の `application_api_client.rb` に出力されていた標準のリトライ処理例 retry_on MyApiClient::NetworkError, wait: 5.seconds, attempts: 3
標準で定義されているエラーハンドラは my_api_client/default_error_handlers.rb から参照できます。
error_handling
は後から定義した物が優先されますので、例えばステータスコード 400
に対しては独自の例外クラスを発生させるようにしたい場合、継承先のクラスで error_handling status_code: 400, raise: MyErrorClass
のように定義すれば、 MyErrorClass
が例外として発生するようになります。
所感
社内のプロダクト用に作った gem ですが、少しずつ自分以外のエンジニアも利用してくれるようになってきました。 一方で、自由度が高過ぎると熟知していないと使えない機能が増えてしまう点を課題感として感じるようになってきました。
なるべく自由度の高い gem を意識しつつ、標準の状態でも高度な機能の恩恵を受けられる状態を目指していきたいと思います。
恐らく次の新機能は async/await
っぽい機能、または sawyer
gem の依存からの脱却なると思います。