[API Gateway]マッピングテンプレートに分岐処理を入れる方法

2024.03.13

こんにちは、稲葉です!

突然ですが、皆さんはAWSのAPI Gatewayのマッピングテンプレートを使用した事がありますでしょうか?

私は最近、案件で使う場面がありました。

AWSのAPI Gatewayのマッピングテンプレートを用いることで、リクエストとレスポンスのハンドリングの柔軟性を大幅に向上させることができます。特に、分岐処理は、複雑なロジックや条件に応じたカスタマイズを可能にします。

しかし、この分岐処理の実装は一筋縄ではいきません。私も実際にAPI Gatewayのマッピングテンプレートを使い、JSONプロパティによる分岐を実現しようとした際には、予想以上の挑戦が待っていました。ドキュメントを読み解くだけでは得られない実践的な知見が必要であり、試行錯誤を繰り返すことになりました。

この記事では、そんな苦労話を通じて、JSONプロパティで分岐するマッピングテンプレートの実装方法を詳しく解説します。私が直面した問題と、それをどのように解決したかのプロセスを共有することで、皆さんのAPI Gatewayでの開発が少しでもスムーズになることを願っています。

はじめに

マッピングテンプレートを使用していて、分岐処理を入れたい場面が多々あると思います。

例えば、他のアプリケーションから呼び出されるAPIなどでユーザーによってリクエストのプロパティが違うため、分岐処理を入れたいなど。

今回は私が実際に直面した上記の状況で、マッピングテンプレートに分岐処理を入れる方法を解説していきます。

苦戦〜解決

はじめに、JSONプロパティに基づく分岐処理を以下のように記述しました。

リクエストボディに含まれるJSONプロパティの userId にアクセスします。このアプリのユーザーからのリクエストの場合、userId が設定されるように分岐処理を行います。他のアプリのユーザーからのリクエストの場合、userId を設定せずに otherAppUserId を設定するようにします。最後に、どのアプリのユーザーからのリクエストであっても必ず送信される id を設定します。

ここで重要なのは、必ず送信されるプロパティを最後に設定することです。この理由は、マッピングテンプレートが最後に余分なカンマがあると正しく動作しないためです。そのため、確実に送信されるプロパティを最後に設定する必要があります。

上記の説明に基づいたコードは以下の通りです。

最初のコード

{ 
#if($input.json("$.userId") && $input.json("$.userId") != "") 
  "userId": $input.json("$.userId"), 
#end 
#if($input.json("$.otherAppUserId") && $input.json("$.otherAppUserId") != "") 
  "otherAppUserId": $input.json("$.otherAppUserId"), 
#end 
"id" : "$method.request.path.id" 
}

しかし、このコードでは条件分岐が機能せず、どちらのアプリのリクエストに対してもすべての値を設定してしまいました。 ちなみに、以下のような似たコードでは条件分岐が正常に機能しています。

#if($method.request.querystring.userId && $method.request.querystring.userId != "")
 "userId": "$method.request.querystring.userId",
#end
#if($method.request.querystring.otherAppUserId && $method.request.querystring.otherAppUserId != "")
 "otherAppUserId": "$method.request.querystring.otherAppUserId",
#end
"id" : "$method.request.path.id"
}

この記述から、クエリパラメータの値にアクセスした際は正常に動作することが確認できます。 これにより、JSONプロパティへのアクセスが上手くいっていないことが問題の原因であると推測しました。

そのため、次にJSONプロパティを一旦変数に格納してから使用するようにしました。

{
#set($userId = $input.json("$.userId"))
#if($userId && $userId != "") 
  "userId": $userId, 
#end 
}

しかし、この書き方もダメでした。今度はどちらのアプリのリクエストに対してもidしか設定しなくなりました。

この辺りから「打つ手なし」な感じになって来ました...

最後に試しで以下のコードを書きました。

最終的なコード

{
      #set($context = $input.path("$"))
      #if($context.userId && $context.userId != "")
        "userId": "$context.userId",
      #end
      #if($context.otherAppUserId && $context.otherAppUserId != "")
        "otherAppUserId": "$context.otherAppUserId",
      #end
      "id" : "$method.request.path.id"
    }

一旦、JSONをcontext変数に格納してから、各プロパティにアクセスするように修正。

この修正の結果、遂に期待通りに条件分岐が動きました!

このアプリのユーザーからのリクエストの場合:

{
  userId: '123456789',
  id: '01'
}

他のアプリのユーザーからのリクエストの場合:

{
  otherAppUserId: 'OA12345',
  id: '02'
}

それぞれ期待する値のみ設定されている。

今まで期待通りに動かなかった原因は、分岐の条件文で直接JSONプロパティにアクセスしていたからだと推測します。

まとめ

ここまで長い道のりでした。

今回マッピングテンプレートに分岐処理を入れる方法を紹介させて頂きました。

この記事の内容が皆さんの役に立てば、嬉しいです。また、実装に苦労した経験がありましたら、それを記事にして共有したいと思います。

最後までお読みいただき、心より感謝申し上げます!

参考文献