AWS SDKのAWSErrorをTypeScrptでハンドリングする

2022/03/20に公開

概要

AWS SDK を用いて TypeScript で開発していると、AWS SDK でCongitoDynamoDB等の処理を実行したときに、例外としてthrowされるAWSErrorをハンドリングしたい場合があります。

具体的には次のようなケースです。

try{
    ...
    await dynamodb.putItem(params).promise();
}catch(e){
    // ここで例外ハンドリングしたい
}

ここで AWS SDK は多くの場合、エラーが発生するとAWSErrorthrowしますが、現時点(2022 年 3 月時点)の AWS SDK 仕様では次のような記載を行うことができません。

NGな記述
try{
    ...
    await dynamodb.putItem(params).promise();
}catch(e){
    if(e instanceof AWSError){ <-ここがエラーになってしまい記述できない
        if (e.code === "XXXXX") {
            // AWSErrorに対する固有のハンドリング
        }
    }
}

TypeScript では、特定のオブジェクトの型を判定し if ブロックで囲むことで、そのブロック内では、特定の型とみなして型安全に処理できるようになっており、タイプガードと呼びますが、AWS SDK のAWSErrorがその記述に対応していないためです。

対応策

タイプガードは固有に作ることができるので、次のような、固有のタイプガード処理を作成しておき、呼び出すことで同様なことを行うことができます。

タイプガード用の関数を定義

import { AWSError } from "aws-sdk";

/**
 * AWSErrorかどうかを判定するタイプガード
 */
export const isAWSError = (arg: any): arg is AWSError => {
  return (
    arg !== null &&
    typeof arg === "object" &&
    typeof arg.code === "string" &&
    typeof arg.message === "string"
  );
};

関数の戻り値の定義として、arg is AWSErrorといった形で記述することでタイプガードとして機能するようになります。
オブジェクトの中に、対象オブジェクトをその型と判定するために必要な要素が存在するかを、typeof arg.code === "string" && typeof arg.message === "string"といった条件式で固有に判定しています。

固有のタイプガードを呼び出して使用可能

try{
    ...
    await dynamodb.putItem(params).promise();
}catch(e){
    if (isAWSError(e)) {
        if (e.code === "XXXXX") {
            // AWSErrorに対する固有のハンドリング
        }
    }
}

タイプガード用の関数を条件式で用いることで、そのブロック内では、対象の型としてみなして処理ができるようになります。

まとめ

AWS SDK がいずれ対応するように思いますが、一旦上記のような形で対応することになるかと思います。
また、このようなテクニックは、ほかのケースでも利用することがありそうですね。

参考サイト

https://typescript-jp.gitbook.io/deep-dive/type-system/typeguard

Discussion