📝

API Gateway のマッピングテンプレートってなんだろ?

2022/09/30に公開約6,900字

DOP の勉強中に API Gateway のマッピングテンプレートが分からなかったので調べてみました。

結論

フロントエンドやバックエンドに必要な情報だけを渡すように定義する API Gateway の機能です。

AWS 公式ドキュメント

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/rest-api-data-transformations.html

API Gateway では、API のメソッドリクエストは、バックエンドで必要となる、該当する統合リクエストペイロードとは異なる形式のペイロードを受け取ることができます。同様に、バックエンドは、フロントエンドで予期されるメソッドレスポンスペイロードとは異なる統合レスポンスペイロードを返す場合があります。API Gateway では、マッピングテンプレートを使用して、ペイロードをメソッドリクエストから該当する統合リクエストにマッピングしたり、統合レスポンスから該当するメソッドレスポンスにマッピングしたりできます。

マッピングテンプレートは、Velocity Template Language (VTL) で表現されるスクリプトであり、JSONPath 式を使用してペイロードに適用されます。

これだけだとよく分かりませんが、何となく必要な情報だけを受け渡すという内容に見受けられます。

Qiita

https://qiita.com/tamura_CD/items/ca8e531f74ea5b82a5b7

API Gatewayの統合レスポンスで設定する、マッピングテンプレートを使えば、バックエンドから受け取ったレスポンスを、ある程度加工する事ができます。

上記の記事で簡単な例があったので分かりやすかったです。
例えば変換前にバックエンドの Lambda などから以下のレスポンスが返されるとします。

{
  "name": "hoge",
  "data": {
    "param1": 10,
    "param2": 20
  }
}

Node.js だと以下のようなレスポンスの記載です。

const res = {
        "name": "fuga",
        "data": {
            "param1": 10,
            "param2": 20
        }
    }
    
return res;

上記のレスポンスを、API Gateway 側で加工することができます。
例えば、nameNAMAE に変えたり、dataDEETA に変えてフロントエンドに送ることができます。

## プロパティ名の置き換え
{
  "NAMAE": $input.json('$.name'),
  "DEETA": $input.json('$.data')
}

実際に Lambda と API Gateway で確認してみました。

Lambda は以下のような簡単な実装です。

index.js
exports.handler = async (event) => {
    const res = {
        "name": "hoge",
        "data": {
            "param1": 10,
            "param2": 20
        }
    }
    return res;
};

API Gateway からは Lambda プロキシ統合を使用せず、いわゆるカスタム統合を使用する設定で、Lambda を呼び出すように設定しました。

マッピングテンプレートを設定せずにテストすると、以下のレスポンスが返ってきました。

{"name":"fuga","data":{"param1":10,"param2":20}}

上記は Lambda から返しているレスポンスと同じ内容です。

今度はマッピングテンプレートを設定してみます。


再度テストすると、今度は Lambda からのレスポンスがマッピングテンプレートで変換され、以下のレスポンスになりました。

{
  "NAMAE": "fuga",
  "DEETA": {"param1":10,"param2":20}
}

こんな具合にリクエストやレスポンスの内容を変換したり、必要な情報だけを渡すようデータを API Gateway 側で加工できる機能がマッピングテンプレートのようです。

ユースケース

リクエストやレスポンスを加工するユースケースはいくつかあるようです。

20190514_AWS-Blackbelt_APIGateway_rev.pdfより

バックエンドとフロントエンドでデータの形式が違う場合に、API Gateway 側で変換することで、双方とも欲しい形式でデータを受け取ることができます。

また、モデルとして受け渡しするデータを定義しておけば、モデルに従わないリクエストが来た時に、API Gateway の時点でエラーを返せるので、バックエンドのエラー処理が不要になる分、バックエンドの負荷も軽減することができるようです。(動画で説明がありました)

[AWS]API Gatewayの本文マッピングテンプレートを理解する | DevelopersIOより

マッピングテンプレートを利用すると、バックエンドへプロキシする情報をカスタマイズすることができます。必要な情報のみ転送することで、バックエンド側の処理をシンプルにすることができます。

例えば、API Gateway > KinesisFirehose > S3 の構成でリクエストデータを保存する場合、必要な情報のみを保存することができます。

API Gateway 側で必要な情報のみに絞ることで、フロントエンドやバックエンドの処理でも必要な情報のみを処理するだけでよい分、実装がシンプルになるようです。
確かに数百行もある JSON データのネストから必要な情報を抽出するより、ネストしていない JSON データから情報を抽出する方が楽ですね。

API Gateway で統合レスポンスのマッピングテンプレートを使って特定条件時にリダイレクトさせる | DevelopersIOより

API Gateway でHTTPバックエンドと統合しているときに、特定APIあるいは特定の統合レスポンスの結果に応じて、クライアントに対してリダイレクト処理を行いたいシーンがありました。
統合バックエンドでリダイレクトヘッダーを生成してAPI Gatewayでは単純にパススルーだけする方法ももちろん出来ますが、何らかの理由でAPI Gateway側で制御したい場合を考えて試してみます。

特殊なケースかもしれませんが、例えば Lambda の実装には手を出してはいけないという要件があった場合に、API Gateway 側で上記のようなリダイレクト処理を実装したい場合にも役に立つようです。

AWS 公式ドキュメントの例

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/models-mappings.html

上記ドキュメントでは、バックエンドから以下のレスポンスが返される API があるという例が記載されています。

{
  "department": "produce",
  "categories": [
    "fruit",
    "vegetables"
  ],
  "bins": [
    {
      "category": "fruit",
      "type": "apples",
      "price": 1.99,
      "unit": "pound",
      "quantity": 232
    },
    {
      "category": "fruit",
      "type": "bananas",
      "price": 0.19,
      "unit": "each",
      "quantity": 112
    },
    {
      "category": "vegetables",
      "type": "carrots",
      "price": 1.29,
      "unit": "bag",
      "quantity": 57
    }
  ]
}

上記のレスポンスのうち、必要な情報は商品の種類、値段、在庫だけの場合、レスポンスには不要な情報が多く含まれています。

そこで、マッピングテンプレートで以下のように記載することで、必要な情報だけを返すようにしています。

{
  "choices": [
#foreach($elem in $inputRoot.bins)
    {
      "kind": "$elem.type",
      "suggestedPrice": "$elem.price per $elem.unit",
      "available": $elem.quantity
    }#if($foreach.hasNext),#end
            
#end
  ]
}

最終的にフロントエンドに返される結果には、商品の種類、値段、在庫だけとなり、見た目もすっきりします。

{
  "choices": [
    {
      "kind": "apples",
      "suggestedPrice": "1.99 per pound",
      "available": 232
    },
    {
      "kind": "bananas",
      "suggestedPrice": "0.19 per each",
      "available": 112
    },
    {
      "kind": "carrots",
      "suggestedPrice": "1.29 per bag",
      "available": 57
    }
  ]
}

VTL について

マッピングテンプレートは、Velocity Template Language (VTL) で表現されるスクリプトであり、JSONPath 式を使用してペイロードに適用されます。

AWS 公式ドキュメントにも記載がある通り、マッピングテンプレートは VTL というスクリプトで記載されるので、初見では分かりづらいかもしれません。
私もよく分かりませんw

ただ、何となくループ処理や配列操作などの感覚は他のプログラミング言語と似ていると思うので、プログラミング経験のある方であればそこまで抵抗はないかなという印象です。

API Gateway には組み込み関数や変数もあるようなので、必要な時にドキュメントを確認しながら検証してみると良いと思います。

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html

まとめ

今回は API Gateway のマッピングテンプレートについて調べてみました。
簡単にまとめてみます。

・リクエスト / レスポンスを API Gateway 側で加工できる機能
・必要な情報だけをフロント / バックエンドに渡すことができる
・フロント / バックエンドの実装をシンプルにできる
・API Gateway の時点で型チェックができるのでバックエンドの負荷を軽減できる

ドキュメントベースの内容でしたが、参考になれば幸いです。

参考サイト

Discussion

ログインするとコメントできます