ドキュメント本文へスキップ
Ruby

エラー

すべての失敗は例外を送出します。拒否用のクラスと応答なし用のクラスがあり、すべての API エラーにリクエスト id が付きます。

エラーを捕捉する

rescue_errors.rb
message = {from: "[email protected]", to: "[email protected]", subject: "Your September invoice", text: "Invoice attached."} begin  client.emails.send(message)rescue OpenEmail::ApiError => error  warn "#{error.code} #{error.param} #{error.message}" if error.validation?  warn client.addresses.list_all.addresses.inspect if error.permission?  warn "try again in #{error.retry_after_seconds} seconds" if error.rate_limited?   warn "#{error.status} #{error.request_id}"  raiserescue OpenEmail::NetworkError => error  warn "no answer in time" if error.timeout?  raiseend

送信時の permission_error は、たいていワークスペースではなくキーの送信範囲、つまりキーに与えられていないドメインやアドレスが原因です。このサンプルが、このキーで送信できるアドレスとして addresses.list_all が返すものを出力しているのはそのためです。

拒否の種類ごとに専用のサブクラスがあるため、rescue は処理するものをクラスで選び、残りは上位へ伝播させることができます。

rescue_by_class.rb
message = {from: "[email protected]", to: "[email protected]", subject: "Your September invoice", text: "Invoice attached."} begin  client.emails.send(message)rescue OpenEmail::ValidationError => error  warn "#{error.param}: #{error.message}"rescue OpenEmail::AuthenticationError, OpenEmail::PermissionError => error  warn "the key cannot do this: #{error.code}"  raiserescue OpenEmail::Error => error  warn "#{error.class}: #{error.message}"  raiseend

エラークラス

クラス発生条件
OpenEmail::Errorgem が定義するすべてのエラーの基底クラスなので、rescue OpenEmail::Error でそのすべてを捕捉できます。ArgumentError は捕捉しません。
OpenEmail::ApiErrorAPI が応答したものの、成功ではなかった場合。status、type、code、param、doc_url、request_id、retry_after_seconds、fields、body を持ちます。サーバー障害のように type が api_error の場合はこのクラスのまま送出され、それ以外の場合は type に対応するサブクラスとして送出されます。
OpenEmail::InvalidRequestError、AuthenticationError、PermissionError、NotFoundError、ConflictError、ValidationError、RateLimitErrorApiError のサブクラスで、type ごとに 1 つあります:invalid_request_error、authentication_error、permission_error、not_found_error、conflict_error、validation_error、rate_limit_error。
OpenEmail::NetworkError応答が届かなかった場合。DNS、TLS、拒否または切断された接続、あるいはタイムアウトです。その下にある例外 original を持ち、これは cause でもあります。タイムアウトが原因のときは timeout? が true です。
OpenEmail::WebhookSignatureErrorOpenEmail.verify_webhook_signature が配信を拒否した場合。
ArgumentError何かが送信される前に送出されます:キーがない、または形式が不正、使えない base_url:、空の id。呼び出しそのものが誤っていることを意味するため、OpenEmail::Error ではなく Ruby の標準クラスです。

ApiError が持つもの

messageString
API 自身の文章で、人が読むために書かれ、問題の値があればそれを示します。安定した識別子ではないので、分岐は `code` で行ってください。
statusInteger
応答の HTTP ステータス。
typeString
`OpenEmail::ERROR_TYPES` の 8 つの値のいずれか。この集合は凍結されており、増えることはありません。ボディが何も示さない場合はステータスから推定されます。
codeString
具体的な失敗内容で、`from_address_forbidden` や `invalid_email_address` などです。拡張に開かれていて追加されていくため、知らないものはその `type` として扱ってください。ボディが API のエラーエンベロープでなかった場合は `unrecognised_response` になります。
paramString or nil
失敗がフィールドを示す場合の、拒否されたフィールド。`to.0` のようなドット区切りのパスです。
doc_urlString or nil
API が示す場合の、この失敗に関するページ。
request_idString or nil
サーバーがリクエストを記録した id。ボディまたは `x-request-id` ヘッダーから取得します。
retry_after_secondsInteger, Float or nil
サーバーが `Retry-After` で求めた待機時間の秒数。数値と日付のどちらで送られても秒に換算されます。送られなかった場合は nil。
fieldsArray<Hash> or nil
問題ごとに 1 つの Hash で、それぞれ `key` と `error` を持ちます。たとえば `forms.subscribe` が回答を 422 `invalid_form_submission` で拒否したときの `{key: "email", error: "email"}` です。エラーが何も挙げない場合は nil。
bodyHash or nil
パース済みのエラーレスポンス全体で、Symbol キーを持ちます。空だったか JSON でなかった場合は nil。
述語メソッドtrue になる条件
auth?type が authentication_error、すなわち 401 の場合。キーがない、資格情報の種類が違う、あるいは当方が発行していないキーであることを意味する。
permission?permission_error、すなわち 403 の場合。キー自体は有効だが、必要なスコープまたは From アドレスを持っていない。
scope_missing?code が insufficient_scope の場合。不足しているスコープを名指しする 403 である。
invalid_request?invalid_request_error、つまり 400:理解できなかったリクエスト。サイズ上限を超えるメッセージは 422 message_too_large として返るため、それを捕まえる述語メソッドは validation? です。
validation?validation_error、すなわち 422 の場合。スキーマが拒否したことを表し、param が該当フィールドを示す。
not_found?not_found_error、すなわち 404 の場合。該当するリソースが存在しない。
conflict?conflict_error、すなわち 409 の場合。対象のリソースは、その操作を行える段階をすでに過ぎている。
rate_limited?rate_limit_error、つまり 429。サーバーが待機時間を示した場合は retry_after_seconds に入ります。
server_error?status が 500 以上の場合。サポートに問い合わせる際は request_id を伝えてください。
retryable?status が 408、429、500、502、503、504 のいずれかの場合。
step_up_required?code が step_up_required の場合。本人がコードを確認するまで、重要な変更の前に OAuth アクセストークンが受け取る 403 です。

ほとんどの述語メソッドは、エンベロープのうち凍結された側である type を読み、各サブクラスは 1 つの type に対応します。code は String のままです。API はそれが拡張に開かれていて追加されていくと保証しているので、知らないものはその type として扱ってください。閉じたリストにすると、新しい失敗の種類を読むために gem のアップグレードが必要になってしまいます。

API のエラーエンベロープではないボディでも OpenEmail::ApiError を送出し、type はステータスから推定され、code は unrecognised_response になります。ボディが JSON ではない成功レスポンスも、同様に送出します。

retryable? が表すのはステータスであり、あなたの呼び出しではありません。繰り返しても安全な呼び出しは、例外を送出する時点ですでにリトライ済みです。また send_quota_exceeded や ai_quota_exceeded のような 429 は、上限がリセットされるまで同じように失敗するため、ループで再試行せずに人に知らせてください。

アダプターが送出した例外は、その呼び出しに許されたリトライを使い切ると OpenEmail::NetworkError になり、元の例外は original と cause に入ります。ただし NameError、TypeError、ArgumentError は別扱いです:アダプターのバグを意味するため、そのまま送出され、リトライされることはありません。

request_id

すべての OpenEmail::ApiError は、サーバーが送ったリクエスト id をエラーボディまたは x-request-id ヘッダーから受け取って保持しており、これがあなたの失敗をサーバーのログの 1 行と結びつける唯一の手がかりです。成功時はパース済みのボディだけを返すため、成功レスポンスで読めるリクエスト id はありません。