From 3a2c81ea8aea4f4a4bc0347cbf424bc37227127f Mon Sep 17 00:00:00 2001 From: George Christman Date: Mon, 29 Jan 2024 16:13:57 -0500 Subject: [PATCH 1/2] websocket sqs integration --- ...efaultTestDeployAssert51A62E2E.assets.json | 19 + ...aultTestDeployAssert51A62E2E.template.json | 36 ++ .../websocket/integ.sqs.js.snapshot/cdk.out | 1 + ...-aws-websocket-sqs-integration.assets.json | 19 + ...ws-websocket-sqs-integration.template.json | 176 +++++++++ .../integ.sqs.js.snapshot/integ.json | 19 + .../integ.sqs.js.snapshot/manifest.json | 149 +++++++ .../websocket/integ.sqs.js.snapshot/tree.json | 371 ++++++++++++++++++ .../test/websocket/integ.sqs.ts | 72 ++++ .../lib/websocket/aws.ts | 9 + .../lib/websocket/integration.ts | 16 + 11 files changed, 887 insertions(+) create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ-aws-websocket-sqs-integration.assets.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ-aws-websocket-sqs-integration.template.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/tree.json create mode 100644 packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.ts diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.assets.json new file mode 100644 index 0000000000000..8807965bba16b --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/cdk.out new file mode 100644 index 0000000000000..1f0068d32659a --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ-aws-websocket-sqs-integration.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ-aws-websocket-sqs-integration.assets.json new file mode 100644 index 0000000000000..8fb1b6982818c --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ-aws-websocket-sqs-integration.assets.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "files": { + "d180cf28b233d302bb39a6b0f591e18057775009ad9c2cf014d786e425cd95f9": { + "source": { + "path": "integ-aws-websocket-sqs-integration.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "d180cf28b233d302bb39a6b0f591e18057775009ad9c2cf014d786e425cd95f9.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ-aws-websocket-sqs-integration.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ-aws-websocket-sqs-integration.template.json new file mode 100644 index 0000000000000..87040beb21176 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ-aws-websocket-sqs-integration.template.json @@ -0,0 +1,176 @@ +{ + "Resources": { + "MessageSQSQueueF7E656B7": { + "Type": "AWS::SQS::Queue", + "Properties": { + "FifoQueue": true, + "QueueName": "MessageSQSQueue.fifo" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "webSocketApi5AB89700": { + "Type": "AWS::ApiGatewayV2::Api", + "Properties": { + "Description": "Send websocket data to SQS which is then processed by a Lambda 2", + "Name": "webSocketApi", + "ProtocolType": "WEBSOCKET", + "RouteSelectionExpression": "$request.body.action" + } + }, + "webSocketApidefaultRouteSQSSendMessageFC4F9133": { + "Type": "AWS::ApiGatewayV2::Integration", + "Properties": { + "ApiId": { + "Ref": "webSocketApi5AB89700" + }, + "CredentialsArn": { + "Fn::GetAtt": [ + "webSocketApiRoleE85311F3", + "Arn" + ] + }, + "IntegrationMethod": "POST", + "IntegrationType": "AWS", + "IntegrationUri": { + "Fn::Join": [ + "", + [ + "arn:aws:apigateway:", + { + "Ref": "AWS::Region" + }, + ":sqs:path/", + { + "Ref": "AWS::AccountId" + }, + "/", + { + "Fn::GetAtt": [ + "MessageSQSQueueF7E656B7", + "QueueName" + ] + } + ] + ] + }, + "PassthroughBehavior": "NEVER", + "RequestParameters": { + "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'" + }, + "RequestTemplates": { + "$default": "Action=SendMessage&MessageGroupId=$input.path('$.MessageGroupId')&MessageDeduplicationId=$context.requestId&MessageAttribute.1.Name=connectionId&MessageAttribute.1.Value.StringValue=$context.connectionId&MessageAttribute.1.Value.DataType=String&MessageAttribute.2.Name=requestId&MessageAttribute.2.Value.StringValue=$context.requestId&MessageAttribute.2.Value.DataType=String&MessageBody=$input.json('$')" + }, + "TemplateSelectionExpression": "\\$default" + } + }, + "webSocketApidefaultRoute749519EC": { + "Type": "AWS::ApiGatewayV2::Route", + "Properties": { + "ApiId": { + "Ref": "webSocketApi5AB89700" + }, + "AuthorizationType": "NONE", + "RouteKey": "$default", + "Target": { + "Fn::Join": [ + "", + [ + "integrations/", + { + "Ref": "webSocketApidefaultRouteSQSSendMessageFC4F9133" + } + ] + ] + } + } + }, + "DevStage520A913F": { + "Type": "AWS::ApiGatewayV2::Stage", + "Properties": { + "ApiId": { + "Ref": "webSocketApi5AB89700" + }, + "AutoDeploy": true, + "StageName": "dev" + } + }, + "webSocketApiRoleE85311F3": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "webSocketApiRoleDefaultPolicyF067C420": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "sqs:SendMessage", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MessageSQSQueueF7E656B7", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "webSocketApiRoleDefaultPolicyF067C420", + "Roles": [ + { + "Ref": "webSocketApiRoleE85311F3" + } + ] + } + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ.json new file mode 100644 index 0000000000000..78a24199fd08e --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/integ.json @@ -0,0 +1,19 @@ +{ + "version": "36.0.0", + "testCases": { + "apigatewayv2-aws-integration-sqs-integ-test/DefaultTest": { + "stacks": [ + "integ-aws-websocket-sqs-integration" + ], + "cdkCommandOptions": { + "deploy": { + "args": { + "rollback": true + } + } + }, + "assertionStack": "apigatewayv2-aws-integration-sqs-integ-test/DefaultTest/DeployAssert", + "assertionStackName": "apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/manifest.json new file mode 100644 index 0000000000000..65bd421a8430d --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/manifest.json @@ -0,0 +1,149 @@ +{ + "version": "36.0.0", + "artifacts": { + "integ-aws-websocket-sqs-integration.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "integ-aws-websocket-sqs-integration.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "integ-aws-websocket-sqs-integration": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "integ-aws-websocket-sqs-integration.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/d180cf28b233d302bb39a6b0f591e18057775009ad9c2cf014d786e425cd95f9.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "integ-aws-websocket-sqs-integration.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "integ-aws-websocket-sqs-integration.assets" + ], + "metadata": { + "/integ-aws-websocket-sqs-integration/MessageSQSQueue/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MessageSQSQueueF7E656B7" + } + ], + "/integ-aws-websocket-sqs-integration/webSocketApi/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "webSocketApi5AB89700" + } + ], + "/integ-aws-websocket-sqs-integration/webSocketApi/$default-Route/SQSSendMessage/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "webSocketApidefaultRouteSQSSendMessageFC4F9133" + } + ], + "/integ-aws-websocket-sqs-integration/webSocketApi/$default-Route/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "webSocketApidefaultRoute749519EC" + } + ], + "/integ-aws-websocket-sqs-integration/DevStage/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "DevStage520A913F" + } + ], + "/integ-aws-websocket-sqs-integration/webSocketApiRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "webSocketApiRoleE85311F3" + } + ], + "/integ-aws-websocket-sqs-integration/webSocketApiRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "webSocketApiRoleDefaultPolicyF067C420" + } + ], + "/integ-aws-websocket-sqs-integration/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/integ-aws-websocket-sqs-integration/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "integ-aws-websocket-sqs-integration" + }, + "apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.template.json", + "terminationProtection": false, + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "apigatewayv2awsintegrationsqsintegtestDefaultTestDeployAssert51A62E2E.assets" + ], + "metadata": { + "/apigatewayv2-aws-integration-sqs-integ-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/apigatewayv2-aws-integration-sqs-integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "apigatewayv2-aws-integration-sqs-integ-test/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/tree.json new file mode 100644 index 0000000000000..07ff51e9701b3 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.js.snapshot/tree.json @@ -0,0 +1,371 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "integ-aws-websocket-sqs-integration": { + "id": "integ-aws-websocket-sqs-integration", + "path": "integ-aws-websocket-sqs-integration", + "children": { + "MessageSQSQueue": { + "id": "MessageSQSQueue", + "path": "integ-aws-websocket-sqs-integration/MessageSQSQueue", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aws-websocket-sqs-integration/MessageSQSQueue/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SQS::Queue", + "aws:cdk:cloudformation:props": { + "fifoQueue": true, + "queueName": "MessageSQSQueue.fifo" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_sqs.CfnQueue", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_sqs.Queue", + "version": "0.0.0" + } + }, + "webSocketApi": { + "id": "webSocketApi", + "path": "integ-aws-websocket-sqs-integration/webSocketApi", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aws-websocket-sqs-integration/webSocketApi/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGatewayV2::Api", + "aws:cdk:cloudformation:props": { + "description": "Send websocket data to SQS which is then processed by a Lambda 2", + "name": "webSocketApi", + "protocolType": "WEBSOCKET", + "routeSelectionExpression": "$request.body.action" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigatewayv2.CfnApi", + "version": "0.0.0" + } + }, + "$default-Route": { + "id": "$default-Route", + "path": "integ-aws-websocket-sqs-integration/webSocketApi/$default-Route", + "children": { + "SQSSendMessage": { + "id": "SQSSendMessage", + "path": "integ-aws-websocket-sqs-integration/webSocketApi/$default-Route/SQSSendMessage", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aws-websocket-sqs-integration/webSocketApi/$default-Route/SQSSendMessage/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGatewayV2::Integration", + "aws:cdk:cloudformation:props": { + "apiId": { + "Ref": "webSocketApi5AB89700" + }, + "credentialsArn": { + "Fn::GetAtt": [ + "webSocketApiRoleE85311F3", + "Arn" + ] + }, + "integrationMethod": "POST", + "integrationType": "AWS", + "integrationUri": { + "Fn::Join": [ + "", + [ + "arn:aws:apigateway:", + { + "Ref": "AWS::Region" + }, + ":sqs:path/", + { + "Ref": "AWS::AccountId" + }, + "/", + { + "Fn::GetAtt": [ + "MessageSQSQueueF7E656B7", + "QueueName" + ] + } + ] + ] + }, + "passthroughBehavior": "NEVER", + "requestParameters": { + "integration.request.header.Content-Type": "'application/x-www-form-urlencoded'" + }, + "requestTemplates": { + "$default": "Action=SendMessage&MessageGroupId=$input.path('$.MessageGroupId')&MessageDeduplicationId=$context.requestId&MessageAttribute.1.Name=connectionId&MessageAttribute.1.Value.StringValue=$context.connectionId&MessageAttribute.1.Value.DataType=String&MessageAttribute.2.Name=requestId&MessageAttribute.2.Value.StringValue=$context.requestId&MessageAttribute.2.Value.DataType=String&MessageBody=$input.json('$')" + }, + "templateSelectionExpression": "\\$default" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigatewayv2.CfnIntegration", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigatewayv2.WebSocketIntegration", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "integ-aws-websocket-sqs-integration/webSocketApi/$default-Route/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGatewayV2::Route", + "aws:cdk:cloudformation:props": { + "apiId": { + "Ref": "webSocketApi5AB89700" + }, + "authorizationType": "NONE", + "routeKey": "$default", + "target": { + "Fn::Join": [ + "", + [ + "integrations/", + { + "Ref": "webSocketApidefaultRouteSQSSendMessageFC4F9133" + } + ] + ] + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigatewayv2.CfnRoute", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigatewayv2.WebSocketRoute", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigatewayv2.WebSocketApi", + "version": "0.0.0" + } + }, + "DevStage": { + "id": "DevStage", + "path": "integ-aws-websocket-sqs-integration/DevStage", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aws-websocket-sqs-integration/DevStage/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::ApiGatewayV2::Stage", + "aws:cdk:cloudformation:props": { + "apiId": { + "Ref": "webSocketApi5AB89700" + }, + "autoDeploy": true, + "stageName": "dev" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigatewayv2.CfnStage", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_apigatewayv2.WebSocketStage", + "version": "0.0.0" + } + }, + "webSocketApiRole": { + "id": "webSocketApiRole", + "path": "integ-aws-websocket-sqs-integration/webSocketApiRole", + "children": { + "ImportwebSocketApiRole": { + "id": "ImportwebSocketApiRole", + "path": "integ-aws-websocket-sqs-integration/webSocketApiRole/ImportwebSocketApiRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "integ-aws-websocket-sqs-integration/webSocketApiRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "apigateway.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "integ-aws-websocket-sqs-integration/webSocketApiRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "integ-aws-websocket-sqs-integration/webSocketApiRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "sqs:SendMessage", + "Effect": "Allow", + "Resource": { + "Fn::GetAtt": [ + "MessageSQSQueueF7E656B7", + "Arn" + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "webSocketApiRoleDefaultPolicyF067C420", + "roles": [ + { + "Ref": "webSocketApiRoleE85311F3" + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "integ-aws-websocket-sqs-integration/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "integ-aws-websocket-sqs-integration/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + }, + "apigatewayv2-aws-integration-sqs-integ-test": { + "id": "apigatewayv2-aws-integration-sqs-integ-test", + "path": "apigatewayv2-aws-integration-sqs-integ-test", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "apigatewayv2-aws-integration-sqs-integ-test/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "apigatewayv2-aws-integration-sqs-integ-test/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "apigatewayv2-aws-integration-sqs-integ-test/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "apigatewayv2-aws-integration-sqs-integ-test/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "apigatewayv2-aws-integration-sqs-integ-test/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests-alpha.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.3.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.ts new file mode 100644 index 0000000000000..a31f25e64a639 --- /dev/null +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.ts @@ -0,0 +1,72 @@ +import { HttpMethod, WebSocketApi, WebSocketStage } from 'aws-cdk-lib/aws-apigatewayv2'; +import * as sqs from 'aws-cdk-lib/aws-sqs'; +import * as iam from 'aws-cdk-lib/aws-iam'; +import { App, Stack, Aws } from 'aws-cdk-lib'; +import { WebSocketAwsIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations'; +import { IntegTest } from '@aws-cdk/integ-tests-alpha'; + +/* + * Stack verification steps: + * 1. Verify manually that the integration has type "AWS" + */ + +const app = new App(); +const stack = new Stack(app, 'integ-aws-websocket-sqs-integration'); + +const sqsMessageQueue = new sqs.Queue(stack, 'MessageSQSQueue', { + fifo: true, + queueName: 'MessageSQSQueue.fifo', +}); + +// API Gateway WebSocket API +const webSocketApi = new WebSocketApi(stack, 'webSocketApi', { + description: 'Send websocket data to SQS which is then processed by a Lambda 2', + routeSelectionExpression: '$request.body.action', +}); + +// Optionally, create a WebSocket stage +new WebSocketStage(stack, 'DevStage', { + webSocketApi: webSocketApi, + stageName: 'dev', + autoDeploy: true, +}); + +// IAM Role for API Gateway +const webSocketApiRole = new iam.Role(stack, 'webSocketApiRole', { + assumedBy: new iam.ServicePrincipal('apigateway.amazonaws.com'), +}); + +webSocketApiRole.addToPolicy( + new iam.PolicyStatement({ + actions: ['sqs:SendMessage'], + effect: iam.Effect.ALLOW, + resources: [sqsMessageQueue.queueArn], + }), +); + +webSocketApi.addRoute('$default', { + integration: new WebSocketAwsIntegration('SQSSendMessage', { + integrationUri: `arn:aws:apigateway:${Aws.REGION}:sqs:path/${Aws.ACCOUNT_ID}/${sqsMessageQueue.queueName}`, + integrationMethod: HttpMethod.POST, + credentialsRole: webSocketApiRole, + passthroughBehavior: 'NEVER', + templateSelectionExpression: '\\$default', + requestTemplates: { + $default: 'Action=SendMessage&MessageGroupId=$input.path(\'$.MessageGroupId\')&MessageDeduplicationId=$context.requestId&MessageAttribute.1.Name=connectionId&MessageAttribute.1.Value.StringValue=$context.connectionId&MessageAttribute.1.Value.DataType=String&MessageAttribute.2.Name=requestId&MessageAttribute.2.Value.StringValue=$context.requestId&MessageAttribute.2.Value.DataType=String&MessageBody=$input.json(\'$\')', + }, + requestParameters: { + 'integration.request.header.Content-Type': '\'application/x-www-form-urlencoded\'', + }, + }), +}); + +new IntegTest(app, 'apigatewayv2-aws-integration-sqs-integ-test', { + testCases: [stack], + cdkCommandOptions: { + deploy: { + args: { + rollback: true, + }, + }, + }, +}); diff --git a/packages/aws-cdk-lib/aws-apigatewayv2-integrations/lib/websocket/aws.ts b/packages/aws-cdk-lib/aws-apigatewayv2-integrations/lib/websocket/aws.ts index 6d7654480b8b4..aade7abd80b20 100644 --- a/packages/aws-cdk-lib/aws-apigatewayv2-integrations/lib/websocket/aws.ts +++ b/packages/aws-cdk-lib/aws-apigatewayv2-integrations/lib/websocket/aws.ts @@ -54,6 +54,13 @@ export interface WebSocketAwsIntegrationProps { * @default - No template selection expression provided. */ readonly templateSelectionExpression?: string; + + /** + * Specifies integration passthrough behaviors. + * + * @default - WHEN_NO_MATCH. + */ + readonly passthroughBehavior?: string; } /** @@ -73,7 +80,9 @@ export class WebSocketAwsIntegration extends WebSocketRouteIntegration { uri: this.props.integrationUri, method: this.props.integrationMethod, credentialsRole: this.props.credentialsRole, + requestParameters: this.props.requestParameters, requestTemplates: this.props.requestTemplates, + passthroughBehavior: this.props.passthroughBehavior, templateSelectionExpression: this.props.templateSelectionExpression, }; } diff --git a/packages/aws-cdk-lib/aws-apigatewayv2/lib/websocket/integration.ts b/packages/aws-cdk-lib/aws-apigatewayv2/lib/websocket/integration.ts index 0eeeeaa97a927..7ee822869ff52 100644 --- a/packages/aws-cdk-lib/aws-apigatewayv2/lib/websocket/integration.ts +++ b/packages/aws-cdk-lib/aws-apigatewayv2/lib/websocket/integration.ts @@ -92,6 +92,13 @@ export interface WebSocketIntegrationProps { * @default - No template selection expression required. */ readonly templateSelectionExpression?: string; + + /** + * Specifies integration passthrough behaviors. + * + * @default - No integration passthrough behavior required. + */ + readonly passthroughBehavior?: string; } /** @@ -112,6 +119,7 @@ export class WebSocketIntegration extends Resource implements IWebSocketIntegrat credentialsArn: props.credentialsRole?.roleArn, requestParameters: props.requestParameters, requestTemplates: props.requestTemplates, + passthroughBehavior: props.passthroughBehavior, templateSelectionExpression: props.templateSelectionExpression, }); this.integrationId = integ.ref; @@ -168,6 +176,7 @@ export abstract class WebSocketRouteIntegration { credentialsRole: config.credentialsRole, requestTemplates: config.requestTemplates, requestParameters: config.requestParameters, + passthroughBehavior: config.passthroughBehavior, templateSelectionExpression: config.templateSelectionExpression, }); } @@ -229,4 +238,11 @@ export interface WebSocketRouteIntegrationConfig { * @default - No template selection expression. */ readonly templateSelectionExpression?: string; + + /** + * Integration passthrough behaviors. + * + * @default - No pass through bahavior. + */ + readonly passthroughBehavior?: string; } From 63b82d2ee9281d14c3d813f9e71a61761b391b3d Mon Sep 17 00:00:00 2001 From: George Christman Date: Mon, 29 Jan 2024 18:04:19 -0500 Subject: [PATCH 2/2] Converted the passthroughBehavior to use an enum. --- .../test/websocket/integ.sqs.ts | 4 +-- .../lib/websocket/aws.ts | 11 ++++-- .../lib/websocket/integration.ts | 36 ++++++++++++++++--- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.ts index a31f25e64a639..49d430bf4ebe2 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-integrations/test/websocket/integ.sqs.ts @@ -1,4 +1,4 @@ -import { HttpMethod, WebSocketApi, WebSocketStage } from 'aws-cdk-lib/aws-apigatewayv2'; +import { HttpMethod, PassthroughBehavior, WebSocketApi, WebSocketStage } from 'aws-cdk-lib/aws-apigatewayv2'; import * as sqs from 'aws-cdk-lib/aws-sqs'; import * as iam from 'aws-cdk-lib/aws-iam'; import { App, Stack, Aws } from 'aws-cdk-lib'; @@ -49,7 +49,7 @@ webSocketApi.addRoute('$default', { integrationUri: `arn:aws:apigateway:${Aws.REGION}:sqs:path/${Aws.ACCOUNT_ID}/${sqsMessageQueue.queueName}`, integrationMethod: HttpMethod.POST, credentialsRole: webSocketApiRole, - passthroughBehavior: 'NEVER', + passthroughBehavior: PassthroughBehavior.NEVER, templateSelectionExpression: '\\$default', requestTemplates: { $default: 'Action=SendMessage&MessageGroupId=$input.path(\'$.MessageGroupId\')&MessageDeduplicationId=$context.requestId&MessageAttribute.1.Name=connectionId&MessageAttribute.1.Value.StringValue=$context.connectionId&MessageAttribute.1.Value.DataType=String&MessageAttribute.2.Name=requestId&MessageAttribute.2.Value.StringValue=$context.requestId&MessageAttribute.2.Value.DataType=String&MessageBody=$input.json(\'$\')', diff --git a/packages/aws-cdk-lib/aws-apigatewayv2-integrations/lib/websocket/aws.ts b/packages/aws-cdk-lib/aws-apigatewayv2-integrations/lib/websocket/aws.ts index aade7abd80b20..33ce2bbd0c033 100644 --- a/packages/aws-cdk-lib/aws-apigatewayv2-integrations/lib/websocket/aws.ts +++ b/packages/aws-cdk-lib/aws-apigatewayv2-integrations/lib/websocket/aws.ts @@ -3,6 +3,7 @@ import { WebSocketIntegrationType, WebSocketRouteIntegrationConfig, WebSocketRouteIntegrationBindOptions, + PassthroughBehavior, } from '../../../aws-apigatewayv2'; import { IRole } from '../../../aws-iam'; @@ -56,11 +57,15 @@ export interface WebSocketAwsIntegrationProps { readonly templateSelectionExpression?: string; /** - * Specifies integration passthrough behaviors. + * Specifies the pass-through behavior for incoming requests based on the + * Content-Type header in the request, and the available mapping templates + * specified as the requestTemplates property on the Integration resource. + * There are three valid values: WHEN_NO_MATCH, WHEN_NO_TEMPLATES, and + * NEVER. * - * @default - WHEN_NO_MATCH. + * @default - No passthrough behavior required. */ - readonly passthroughBehavior?: string; + readonly passthroughBehavior?: PassthroughBehavior } /** diff --git a/packages/aws-cdk-lib/aws-apigatewayv2/lib/websocket/integration.ts b/packages/aws-cdk-lib/aws-apigatewayv2/lib/websocket/integration.ts index 7ee822869ff52..30e9d6b51e9c2 100644 --- a/packages/aws-cdk-lib/aws-apigatewayv2/lib/websocket/integration.ts +++ b/packages/aws-cdk-lib/aws-apigatewayv2/lib/websocket/integration.ts @@ -32,6 +32,30 @@ export enum WebSocketIntegrationType { AWS = 'AWS', } +/** + * Integration Passthrough Behavior + */ +export enum PassthroughBehavior { + /** + * Passes the request body for unmapped content types through to the + * integration back end without transformation. + */ + WHEN_NO_MATCH = 'WHEN_NO_MATCH', + + /** + * Rejects unmapped content types with an HTTP 415 'Unsupported Media Type' + * response + */ + NEVER = 'NEVER', + + /** + * Allows pass-through when the integration has NO content types mapped to + * templates. However if there is at least one content type defined, + * unmapped content types will be rejected with the same 415 response. + */ + WHEN_NO_TEMPLATES = 'WHEN_NO_TEMPLATES' +} + /** * The integration properties */ @@ -94,11 +118,15 @@ export interface WebSocketIntegrationProps { readonly templateSelectionExpression?: string; /** - * Specifies integration passthrough behaviors. + * Specifies the pass-through behavior for incoming requests based on the + * Content-Type header in the request, and the available mapping templates + * specified as the requestTemplates property on the Integration resource. + * There are three valid values: WHEN_NO_MATCH, WHEN_NO_TEMPLATES, and + * NEVER. * - * @default - No integration passthrough behavior required. + * @default - No passthrough behavior required. */ - readonly passthroughBehavior?: string; + readonly passthroughBehavior?: PassthroughBehavior } /** @@ -244,5 +272,5 @@ export interface WebSocketRouteIntegrationConfig { * * @default - No pass through bahavior. */ - readonly passthroughBehavior?: string; + readonly passthroughBehavior?: PassthroughBehavior; }