未分類

CDKでAPI Gateway経由SNSトピックメッセージを作成してLambdaを起動する

API GatewayからSNSトピックメッセージを作成して、目的が違う複数のLambdaを使い分けて起動しようとしましたがインターネットに情報が少なく実装するのに時間がかかってしまったのでまとめておきます。

SubscriptionFilterには2つの使い方がある

メッセージ本文から取り出す方法(filter_policy_with_message_body)と、メッセージ種別(filter_policy)から取り出す方法があります。

ここでfilter_policyしか見つからず相当な時間を費やしました。

API Gateway経由ではメッセージ種別の送信ができませんでした。

わたしが知らないだけかも知れません。

API GatewayかSNSトピックメッセージを配信するにはメッセージ本文(Message)にいれるしかありません。

メッセージ本文から取り出す方法

topic.add_subscription(aws_sns_subscriptions.LambdaSubscription(lambda_func,
    filter_policy_with_message_body = {
        "background" : aws_sns.FilterOrPolicy.policy({
                "color": aws_sns.FilterOrPolicy.filter(aws_sns.SubscriptionFilter.string_filter(allowlist=["red", "orange"]))
        })
    }
))

https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_sns/FilterOrPolicy.html

{
    "background": {
        "color": [
            "orange"
        ]
    },
}

この時のメッセージ本文

どうしてもメッセージ種別を使いたい場合

API Gatewayから直接SNSトピックメッセージを発行するのはやめて、Lambdaを経由することにより可能となります。

https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_sns/SubscriptionFilter.html

メッセージ本文にSNSトピックメッセージのパラメータを追加したくない場合には、こちらの選択もありだと思います。

参考:SNSトピックメッセージを発行するAPI Gatewayの作成

参考になるかも知れないので、実際に動作したプログラムを添付しておきます。

api_resource.add_method(
    api_method,
    aws_apigateway.AwsIntegration(
        service = "sns",
        region = "ap-northeast-1",
        integration_http_method =  "POST",
        action = "Publish",
        options = {
            "credentials_role": params.apigw_role,
            "request_parameters": {
                "integration.request.querystring.Message": "method.request.body",
                "integration.request.querystring.TargetArn": f"'{params.settings['sns_topic_makeFile_arn']}'",
            },
            "integration_responses": [
                {
                    "statusCode": "200",
                    # SNSのレスポンスをそのまま返したい場合(パススルー)は記述しなくて良い
                    "responseTemplates": {
                        "application/json": '{ "status": "success" }',
                    },
                },
                {
                "statusCode": "400",
                "selectionPattern": "4\\d{2}",
                    "responseTemplates": {
                        "application/json": '{ message: "Invalid request." }',
                    },
                },
                {
                "statusCode": "500",
                "selectionPattern": "5\\d{2}",
                    "responseTemplates": {
                        "application/json": '{ message: "Internal server error." }',
                    },
                },
            ],
        },
    ),
    authorizer=params.api_authorizer,
    method_responses = [
        {
            "statusCode": "200",
        },
        {
            "statusCode": "400",
        },
        {
            "statusCode": "500",
        },
    ]
)