0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

API GatewayのパラメータバリデーションとマッピングテンプレートでLambda呼び出しコストを削減する方法

Posted at

概要

API Gatewayのメソッドリクエストで必須パラメータを検証し、不正リクエストを400エラーで即座に拒否することでLambda実行コストを削減できます。さらに統合リクエストのマッピングテンプレートでパラメータを安全に整形し、OpenSearch Serviceへの検索処理を効率化する実装パターンを解説します。


目次

  1. はじめに
  2. API Gatewayのリクエスト処理フローとレイヤー構造
  3. HTTP統合とLambda統合の違い
  4. メソッドリクエストでのパラメータバリデーション
  5. 統合リクエストでのマッピングテンプレート活用
  6. 実装例とコード
  7. ベストプラクティスと注意点
  8. 料金比較とコスト削減効果
  9. 終わりに
  10. 参考文献・参考サイト

1. はじめに

API Gatewayを使ったサーバーレスアーキテクチャでは、バックエンドのLambda関数が不正なリクエストを受け取り、エラー処理のためだけに実行されるケースがあります。これは無駄なコストを発生させるだけでなく、Lambda側でのバリデーションロジックの複雑化も招きます。

本記事では、API Gatewayのメソッドリクエストレイヤーで必須パラメータを検証し、不正リクエストをLambda呼び出し前に400エラーで即座に拒否する設計パターンを解説します。さらに、統合リクエストのマッピングテンプレートを使ってパラメータを安全に整形し、OpenSearch Serviceへの検索クエリとして渡す実践的な実装方法を紹介します。

この設計パターンにより、Lambda実行回数を削減してコストを抑制し、セキュリティも強化できます。


2. API Gatewayのリクエスト処理フローとレイヤー構造

API Gatewayは、クライアントからのリクエストを4つのレイヤーで処理します。各レイヤーの役割を理解することが、効果的なバリデーションとデータ変換の実装に不可欠です。

image.png

4つのレイヤーとその役割

レイヤー名 処理タイミング 主な役割
メソッドリクエスト リクエスト受信直後 パラメータの検証、認証・認可、APIキーチェック
統合リクエスト バックエンド呼び出し前 リクエストデータの変換、マッピングテンプレートの適用
統合レスポンス バックエンドからの応答受信後 レスポンスデータの変換、ステータスコードのマッピング
メソッドレスポンス クライアントへの応答直前 レスポンスヘッダーの設定、CORSの設定

メソッドリクエストレイヤーでバリデーションを行うことで、不正なリクエストはここで処理が止まり、後続のレイヤーやバックエンドには到達しません。これが、Lambda実行コストを削減できる理由です。


3. HTTP統合とLambda統合の違い

API Gatewayには複数の統合タイプがありますが、特に重要なのがHTTP統合Lambda統合です。マッピングテンプレートの扱いに大きな違いがあるため、適切な選択が必要です。

Lambda統合の2つのタイプ

統合タイプ 正式名称 マッピングテンプレート リクエスト/レスポンス形式 用途
Lambda プロキシ統合 AWS_PROXY 使用不可 固定形式(イベントオブジェクト) シンプルな実装、Lambda側で柔軟に処理
Lambda 非プロキシ統合 AWS 使用可能 自由に変換可能 リクエスト/レスポンスの細かい制御が必要な場合

HTTP統合の2つのタイプ

統合タイプ 正式名称 マッピングテンプレート 用途
HTTP プロキシ統合 HTTP_PROXY 使用不可 バックエンドへそのまま転送
HTTP 非プロキシ統合 HTTP 使用可能 HTTPエンドポイントへのリクエスト変換

本記事で使用する統合タイプ

本記事ではLambda 非プロキシ統合(AWS) を使用します。これにより、マッピングテンプレートでクエリ文字列を取得し、JSON形式に整形してLambdaに渡すことができます。

AWS公式ドキュメント「API Gateway API 統合タイプの選択」( https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-api-integration-types.html )では、『プロキシ統合では、クライアントから送信されたリクエストデータをそのままバックエンドに渡し、バックエンドからのレスポンスをそのままクライアントに返します』と説明されています。


4. メソッドリクエストでのパラメータバリデーション

メソッドリクエストレイヤーでパラメータを検証することで、Lambda呼び出し前に不正リクエストを拒否できます。

必須パラメータの宣言

クエリ文字列パラメータfilterを必須とする設定例です。AWS CLIを使用します。

# API Gatewayリソースの作成
aws apigateway create-resource \
  --rest-api-id abc123xyz \
  --parent-id root123 \
  --path-part search \
  --region ap-northeast-1

# GETメソッドの作成
aws apigateway put-method \
  --rest-api-id abc123xyz \
  --resource-id res456 \
  --http-method GET \
  --authorization-type NONE \
  --request-parameters method.request.querystring.filter=true \
  --region ap-northeast-1

--request-parameters method.request.querystring.filter=trueの部分で、クエリ文字列パラメータfilterを必須(true)と宣言しています。

リクエストバリデータの設定

さらに厳密な検証を行うには、リクエストバリデータを作成します。

# リクエストバリデータの作成
aws apigateway create-request-validator \
  --rest-api-id abc123xyz \
  --name "Validate-Query-Parameters" \
  --validate-request-parameters true \
  --region ap-northeast-1

# メソッドにバリデータを適用
aws apigateway update-method \
  --rest-api-id abc123xyz \
  --resource-id res456 \
  --http-method GET \
  --patch-operations \
    op=replace,path=/requestValidatorId,value=validator789 \
  --region ap-northeast-1

バリデーション失敗時の動作

必須パラメータが不足している場合、API Gatewayは即座に以下のようなレスポンスを返します。

{
  "message": "Missing required request parameters: [filter]"
}

HTTPステータスコードは400 Bad Requestとなり、Lambdaは一切呼び出されません。これにより、無駄なLambda実行を防ぎ、コストを削減できます。


5. 統合リクエストでのマッピングテンプレート活用

統合リクエストレイヤーでマッピングテンプレートを使用し、クエリ文字列を取得してJSON形式に整形します。

マッピングテンプレートの基本

マッピングテンプレートはVTL(Velocity Template Language) で記述します。$input変数を使って、リクエストの各要素にアクセスできます。

クエリ文字列の取得と整形

# 統合リクエストの設定(Lambda 非プロキシ統合)
aws apigateway put-integration \
  --rest-api-id abc123xyz \
  --resource-id res456 \
  --http-method GET \
  --type AWS \
  --integration-http-method POST \
  --uri "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:123456789012:function:SearchFunction/invocations" \
  --request-templates '{"application/json":"{\"searchQuery\": \"$input.params('\'filter'\'')\"}"}' \
  --region ap-northeast-1

マッピングテンプレートの内容(見やすく整形):

{
  "searchQuery": "$input.params('filter')"
}

$input.params('filter')でクエリ文字列filterの値を取得し、searchQueryというキーでJSON化しています。

Lambdaでの受け取り

Lambda関数では、以下のようにイベントオブジェクトから値を取得できます。

def lambda_handler(event, context):
    search_query = event['searchQuery']
    # OpenSearch Serviceへの検索処理
    # ...

Lambda 非プロキシ統合では、マッピングテンプレートで定義した形式がそのままeventとして渡されます。


6. 実装例とコード

実際の運用を想定した完全な実装例を示します。

API Gateway設定の完全例

# 1. REST APIの作成
aws apigateway create-rest-api \
  --name "SearchAPI" \
  --description "OpenSearch integration with parameter validation" \
  --region ap-northeast-1

# 2. リソースの作成
aws apigateway create-resource \
  --rest-api-id abc123xyz \
  --parent-id root123 \
  --path-part search \
  --region ap-northeast-1

# 3. リクエストバリデータの作成
aws apigateway create-request-validator \
  --rest-api-id abc123xyz \
  --name "QueryParamValidator" \
  --validate-request-parameters true \
  --region ap-northeast-1

# 4. GETメソッドの作成(必須パラメータ指定)
aws apigateway put-method \
  --rest-api-id abc123xyz \
  --resource-id res456 \
  --http-method GET \
  --authorization-type NONE \
  --request-parameters method.request.querystring.filter=true \
  --request-validator-id validator789 \
  --region ap-northeast-1

# 5. Lambda統合の設定(非プロキシ統合)
aws apigateway put-integration \
  --rest-api-id abc123xyz \
  --resource-id res456 \
  --http-method GET \
  --type AWS \
  --integration-http-method POST \
  --uri "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:123456789012:function:SearchFunction/invocations" \
  --request-templates file://mapping-template.json \
  --region ap-northeast-1

# 6. 統合レスポンスの設定
aws apigateway put-integration-response \
  --rest-api-id abc123xyz \
  --resource-id res456 \
  --http-method GET \
  --status-code 200 \
  --region ap-northeast-1

# 7. メソッドレスポンスの設定
aws apigateway put-method-response \
  --rest-api-id abc123xyz \
  --resource-id res456 \
  --http-method GET \
  --status-code 200 \
  --region ap-northeast-1

# 8. デプロイ
aws apigateway create-deployment \
  --rest-api-id abc123xyz \
  --stage-name prod \
  --region ap-northeast-1

マッピングテンプレートファイル(mapping-template.json)

{
  "application/json": "{\"searchQuery\": \"$input.params('filter')\", \"timestamp\": \"$context.requestTime\"}"
}

このテンプレートは、クエリ文字列filterと、リクエスト時刻をLambdaに渡します。

Lambda関数の実装例(Python)

import json
import boto3
from opensearchpy import OpenSearch, RequestsHttpConnection
from requests_aws4auth import AWS4Auth

# OpenSearch Serviceクライアントの初期化
region = 'ap-northeast-1'
service = 'es'
credentials = boto3.Session().get_credentials()
awsauth = AWS4Auth(
    credentials.access_key,
    credentials.secret_key,
    region,
    service,
    session_token=credentials.token
)

host = 'search-domain-xxx.ap-northeast-1.es.amazonaws.com'
opensearch_client = OpenSearch(
    hosts=[{'host': host, 'port': 443}],
    http_auth=awsauth,
    use_ssl=True,
    verify_certs=True,
    connection_class=RequestsHttpConnection
)

def lambda_handler(event, context):
    # マッピングテンプレートから受け取ったパラメータ
    search_query = event.get('searchQuery', '')
    
    # 簡易的なバリデーション(追加の安全対策)
    if not search_query or len(search_query) > 100:
        return {
            'statusCode': 400,
            'body': json.dumps({'error': 'Invalid search query'})
        }
    
    # OpenSearch Serviceへの検索
    try:
        response = opensearch_client.search(
            index='products',
            body={
                'query': {
                    'match': {
                        'name': search_query
                    }
                }
            }
        )
        
        return {
            'statusCode': 200,
            'body': json.dumps({
                'results': response['hits']['hits'],
                'total': response['hits']['total']['value']
            })
        }
    
    except Exception as e:
        print(f"Error: {str(e)}")
        return {
            'statusCode': 500,
            'body': json.dumps({'error': 'Search failed'})
        }

Lambda 非プロキシ統合では、返却する形式をstatusCodebodyを含むオブジェクトとする必要があります。


7. ベストプラクティスと注意点

パラメータバリデーションで検証すべき項目

検証項目 API Gatewayで可能 Lambda側で推奨
必須パラメータの存在 -
パラメータの型(文字列、数値) ✓(JSONスキーマ使用時)
文字列の長さ制限 ✓(JSONスキーマ使用時)
特殊文字のエスケープ -
ビジネスロジックの検証 -

API Gatewayでは構造的なバリデーション、Lambdaではビジネスロジックに関するバリデーションと役割分担することで、効率的な設計になります。

マッピングテンプレートでのエスケープ処理

VTLでは、特殊文字のエスケープが必要です。

{
  "searchQuery": "$util.escapeJavaScript($input.params('filter'))"
}

$util.escapeJavaScript()を使用することで、シングルクォートやダブルクォートなどを安全にエスケープできます。

CloudWatchログでのデバッグ

マッピングテンプレートのデバッグには、CloudWatch Logsを有効化します。

# ステージ設定でログを有効化
aws apigateway update-stage \
  --rest-api-id abc123xyz \
  --stage-name prod \
  --patch-operations \
    op=replace,path=/logging/loglevel,value=INFO \
    op=replace,path=/logging/dataTrace,value=true \
  --region ap-northeast-1

ログには、マッピングテンプレート適用前後のリクエストボディが記録されます。

セキュリティ上の考慮点

OpenSearch Serviceへの検索クエリとしてパラメータを使用する場合、以下の対策が重要です。

  • インジェクション対策:Lambda側で入力値のサニタイジングを実施
  • 長さ制限:極端に長いクエリ文字列を拒否(DoS対策)
  • 許可リスト方式:可能であれば、許可された文字のみを受け入れる

AWS公式ドキュメント「API Gateway でのデータ保護」( https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/data-protection.html )では、『入力の検証を実装して、悪意のある入力が API に渡されるのを防ぎます』と推奨されています。


8. 料金比較とコスト削減効果

Lambda実行コストの試算

ap-northeast-1(東京リージョン)での料金(2024年時点):

項目 料金
Lambda リクエスト料金 100万リクエストあたり$0.20
Lambda 実行時間料金(128MB) 100万GB秒あたり$16.67
API Gateway リクエスト料金 100万リクエストあたり$4.25(最初の3億リクエスト)

コスト削減の具体例

前提条件

  • 月間100万リクエスト
  • うち20%(20万リクエスト)が必須パラメータ不足
  • Lambda実行時間:平均200ms(0.2秒)、メモリ128MB

パラメータバリデーションなしの場合

Lambda実行コスト = (1,000,000 × $0.20/1,000,000) + 
                  (1,000,000 × 0.2秒 × 128MB/1024 × $16.67/1,000,000)
                = $0.20 + $0.42 = $0.62

パラメータバリデーションありの場合

Lambda実行コスト = (800,000 × $0.20/1,000,000) + 
                  (800,000 × 0.2秒 × 128MB/1024 × $16.67/1,000,000)
                = $0.16 + $0.33 = $0.49

月間削減額:$0.62 - $0.49 = $0.13(約20%削減)

API Gatewayのリクエスト料金は変わりませんが、Lambda実行コストを削減できます。リクエスト数や不正リクエストの割合が大きいほど、削減効果は高くなります。

最新の料金情報は、AWS公式の「AWS Lambda 料金」( https://aws.amazon.com/jp/lambda/pricing/ )および「Amazon API Gateway の料金」( https://aws.amazon.com/jp/api-gateway/pricing/ )をご確認ください。


9. 終わりに

本記事では、API Gatewayのメソッドリクエストレイヤーでパラメータバリデーションを行い、統合リクエストレイヤーのマッピングテンプレートでデータを整形する設計パターンを解説しました。

この設計により、以下のメリットが得られます:

  • コスト削減:不正リクエストによる無駄なLambda実行を防止
  • セキュリティ向上:入力検証を多層化し、バックエンドの負担を軽減
  • 保守性向上:バリデーションロジックをAPI Gatewayに集約

Lambda 非プロキシ統合とマッピングテンプレートは、初見では複雑に感じるかもしれませんが、柔軟なリクエスト/レスポンス変換を実現する強力な機能です。

次のステップ

  • JSONスキーマを使った高度なバリデーション(型、形式、範囲の検証)
  • API Gatewayのリクエストスロットリング設定でDDoS対策
  • AWS WAFとの組み合わせによるセキュリティ強化
  • CloudWatch Insightsを使った不正リクエストの分析

10. 参考文献・参考サイト

AWS公式ドキュメント

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?