Amazon Web Services ブログ

AWS SDK for JavaScript (v3) モジュールでのエラー処理

この記事は Error Handling in Modular AWS SDK for JavaScript (v3) を翻訳したものです。

AWS SDK for JavaScript (v3) モジュールのバージョン3.53.0 では、instanceof 演算子でサービス例外のアサートをサポートするAWS サービス例外の具象クラスが導入されました。この記事では、その使い方と、エラーハンドリングの方法がどのように改善されるかについて説明します。

導入理由について

これまでAWS SDK for JavaScript (v3) のユーザーは、サービス例外をプレーンなJavaScript オブジェクトとして投げていたため、サービス例外の型をアサートすることができませんでした。アプリケーションコードは、以下のコードに示すように、オブジェクトキー name の値を期待されるエラーコード文字列と比較することによってのみ、例外を処理することができました。

try {
  await client.send(someCommand);
} catch (e) {
  if (e.name === "InvalidSignatureException") {
    // Handle InvalidSignatureException
  } else if (e.name === "ResourceNotFoundException") {
    // Handle ResourceNotFoundException
  } else if (e.name === "FooServiceException") {
    // Handle all other server-side exceptions from Foo service
  } else {
    // Handle errors from SDK
  }
}

その結果、処理するすべてのエラーのエラーコードを把握し、アプリケーションに期待されるエラーコードをハードコードする必要がありました。さらに、TypeScript のコードだけが、キャッチした例外を提供されているサービス例外インターフェイスにキャストすることができました。JavaScript のコードでは、IntelliSense のコード補完機能を使って、サービス例外からいずれのtraits にもアクセスすることができませんでした。

この機能を改善する要望は複数寄せられていました。例えば、AWS SDE のDaniel Lees は社内のslack チャンネルでこの質問をしていました。

こんにちは、なぜjs aws sdk v3 はErrors やエラーのサブクラスを投げないのか、誰か知っていますか?あるいは、少なくともエラーの形をしたオブジェクトを投げないのでしょうか?技術的には、Errors やエラーのサブクラスを投げることはjavascript の要件ではありませんが、一般的にはeslinttypescript-eslint ではグッドプラクティスと考えられています

GitHubユーザーのLambros Petrou はaws/aws-sdk-js-v3/#2007 で次のように述べています。

XxxCommandInput/Output 型を利用したハッピーなケースと同じように、エラーレスポンスを使いやすいTypeScript の具体的な型定義があるといいですね。

クラスを使ってサービス例外を処理する方法

この変更の結果、SDK はサーバーサイドからの例外をすべて特定のクラスで構成するようになりました。以下のように、キャッチした例外が期待されるものであるかどうかを instanceof を使ってアサートすることができます。

import {
  InvalidSignatureException,
  ResourceNotFoundException,
  FooServiceException,
} from "@aws-sdk/client-foo";

try {
  await client.send(someCommand);
} catch (e) {
  if (e instanceof InvalidSignatureException) {
    // Handle InvalidSignatureException
  } else if (e instanceof ResourceNotFoundException) {
    // Handle ResourceNotFoundException
  } else if (e instanceof FooServiceException) {
    // Handle all other server-side exceptions from Foo service
  } else {
    // Other errors
  }
}

上の例では、InvalidSignatureExceptionResourceNotFoundExceptionsomeCommand によってスローされる例外で、特別な処理が必要です。e instanceof InvalidSignatureException ステートメントを使用すると、例外が与えられたクラスのインスタンスであるかどうかをアサートすることができます。

一旦エラーがアサーションされると、e は自動的に与えられた例外の型にキャストされます。その結果、以下のように使用しているIDEからコードハイライトとオートコンプリートを取得することができます。

エラー処理コードブロックでは、指定されたあらゆるサーバーサイドの例外をデフォルトのケースとして処理することは、一般的なユースケースです。上のコードで示したように、FooServiceException はまさにこのケースに対応するものです。各サービスクライアントの場合、すべてのサーバーサイド例外のベースクラスは [ServiceId]ServiceException という名前になります。例えば、S3サービスのベースクラス名は、S3ServiceException と呼ばれます。

この変更は後方互換性があり、既存のエラー処理コードはすべて動作します。また、name の値でエラーをアサートすることも可能です。

サービス例外クラスのふるまい

各サーバーサイド例外のインスタンスには、エラー処理ロジックを補助する便利な共有traits が用意されています。

以下のグラフは、その概要を示しています。

v3-exceptions-class-1

以下は、利用可能なエラーtraits の内訳です。

  • name: 与えられた例外のエラーコード。通常、クラス名と同じです。
  • message: エラーの原因を示すエラーメッセージ。
  • $response: 生のレスポンスオブジェクト (例: HTTP Incoming Message ) へのオプショナルな列挙不可能な参照。
  • $retryable: クライアントが再試行してもよいエラーであることを示すオプショナルなハッシュ。
  • $fault: 与えられた例外について、’クライアント’ あるいは ‘サーバー’ のどちらに問題があるのかを示す文字列。
  • stack: 与えられたエラーのスタックトレース。

ご意見をお聞かせください

皆様からのフィードバックをお待ちしています。GitHub で issue を作成して、ご意見やご要望をお聞かせください。

Allan Zheng

Allanは、Node.js 版とブラウザ版の AWS SDK for Javascript のメンテナーです。彼は、ユーザーがAWS を使いこなすためのツールを構築しています。GitHubで @AllanZhengYP を見つけてください。

翻訳はソリューションアーキテクトの杉山が担当しました。原文はこちらです。