Skip to content

Commit f431021

Browse files
authored
feat(apigateway): support response streaming with response transfer mode (#36155)
### Issue # (if applicable) Closes #36156. ### Reason for this change AWS announced support for response streaming in Amazon API Gateway to significantly improve the responsiveness of your REST APIs by progressively streaming response payloads back to the client. see: https://aws.amazon.com/blogs/compute/building-responsive-apis-with-amazon-api-gateway-response-streaming/ This feature uses the `responseTransferMode` parameter for integrations. see: https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-apigateway-method-integration.html#cfn-apigateway-method-integration-responsetransfermode ### Description of changes Added `responseTransferMode` to `IntegrationOptions`. Also, in the case of Lambda integrations, the URI path changes for streams (for example: `arn:aws:apigateway:${APIGW_REGION}:lambda:path/2021-11-15/functions/${FN_ARN}/response-streaming-invocations`), so I changed that in `LambdaIntegration` as well. ```ts const path = options.responseTransferMode === ResponseTransferMode.STREAM ? `2021-11-15/functions/${handler.functionArn}/response-streaming-invocations` : `2015-03-31/functions/${handler.functionArn}/invocations`; ``` ref: - https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html#API_InvokeWithResponseStream_RequestSyntax - https://aws.amazon.com/jp/blogs/compute/building-responsive-apis-with-amazon-api-gateway-response-streaming/#:~:text=Setting%20response%20transfer%20mode%20using%20infrastructure%2Das%2Dcode%20(IaC)%20frameworks%2C%20such%20as%20AWS%20CloudFormation.%20Note%20the%20/response%2Dstreaming%2Dinvocations%20Uri%20fragment%2C%20it%20tells%20API%20Gateway%20to%20use%20the%20Lambda%20InvokeWithResponseStreaming%20endpoint%3A - `Note the /response-streaming-invocations Uri fragment, it tells API Gateway to use the Lambda [InvokeWithResponseStreaming](https://docs.aws.amazon.com/lambda/latest/api/API_InvokeWithResponseStream.html) endpoint:` ### Describe any new or updated permissions being added ### Description of how you validated changes Both unit tests and integ tests. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent d074024 commit f431021

File tree

16 files changed

+33763
-2
lines changed

16 files changed

+33763
-2
lines changed

packages/@aws-cdk-testing/framework-integ/test/aws-apigateway/test/integ.restapi-stream.js.snapshot/RestApiStreamStack.assets.json

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
{
2+
"Resources": {
3+
"myfnServiceRole7822DC24": {
4+
"Type": "AWS::IAM::Role",
5+
"Properties": {
6+
"AssumeRolePolicyDocument": {
7+
"Statement": [
8+
{
9+
"Action": "sts:AssumeRole",
10+
"Effect": "Allow",
11+
"Principal": {
12+
"Service": "lambda.amazonaws.com"
13+
}
14+
}
15+
],
16+
"Version": "2012-10-17"
17+
},
18+
"ManagedPolicyArns": [
19+
{
20+
"Fn::Join": [
21+
"",
22+
[
23+
"arn:",
24+
{
25+
"Ref": "AWS::Partition"
26+
},
27+
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
28+
]
29+
]
30+
}
31+
]
32+
}
33+
},
34+
"myfn8C66D016": {
35+
"Type": "AWS::Lambda::Function",
36+
"Properties": {
37+
"Code": {
38+
"ZipFile": "exports.handler = awslambda.streamifyResponse(async (event, responseStream, context) => {\n const metadata = {\n statusCode: 200,\n headers: { 'Content-Type': 'text/plain' }\n };\n responseStream = awslambda.HttpResponseStream.from(responseStream, metadata);\n responseStream.write('Hello, ');\n await new Promise(resolve => setTimeout(resolve, 100));\n responseStream.write('streaming ');\n await new Promise(resolve => setTimeout(resolve, 100));\n responseStream.write('world!');\n responseStream.end();\n });"
39+
},
40+
"Handler": "index.handler",
41+
"Role": {
42+
"Fn::GetAtt": [
43+
"myfnServiceRole7822DC24",
44+
"Arn"
45+
]
46+
},
47+
"Runtime": "nodejs24.x"
48+
},
49+
"DependsOn": [
50+
"myfnServiceRole7822DC24"
51+
]
52+
},
53+
"ApiF70053CD": {
54+
"Type": "AWS::ApiGateway::RestApi",
55+
"Properties": {
56+
"Name": "Api"
57+
}
58+
},
59+
"ApiDeploymentB17BE62D7de2852053d3078d3cd07c9ca6f4d12c": {
60+
"Type": "AWS::ApiGateway::Deployment",
61+
"Properties": {
62+
"Description": "Automatically created by the RestApi construct",
63+
"RestApiId": {
64+
"Ref": "ApiF70053CD"
65+
}
66+
},
67+
"DependsOn": [
68+
"ApiPOST9384DEBA"
69+
],
70+
"Metadata": {
71+
"aws:cdk:do-not-refactor": true
72+
}
73+
},
74+
"ApiDeploymentStageprod3EB9684E": {
75+
"Type": "AWS::ApiGateway::Stage",
76+
"Properties": {
77+
"DeploymentId": {
78+
"Ref": "ApiDeploymentB17BE62D7de2852053d3078d3cd07c9ca6f4d12c"
79+
},
80+
"RestApiId": {
81+
"Ref": "ApiF70053CD"
82+
},
83+
"StageName": "prod"
84+
}
85+
},
86+
"ApiPOSTApiPermissionRestApiStreamStackApi1C847828POST2283EDE7": {
87+
"Type": "AWS::Lambda::Permission",
88+
"Properties": {
89+
"Action": "lambda:InvokeFunction",
90+
"FunctionName": {
91+
"Fn::GetAtt": [
92+
"myfn8C66D016",
93+
"Arn"
94+
]
95+
},
96+
"Principal": "apigateway.amazonaws.com",
97+
"SourceArn": {
98+
"Fn::Join": [
99+
"",
100+
[
101+
"arn:",
102+
{
103+
"Ref": "AWS::Partition"
104+
},
105+
":execute-api:",
106+
{
107+
"Ref": "AWS::Region"
108+
},
109+
":",
110+
{
111+
"Ref": "AWS::AccountId"
112+
},
113+
":",
114+
{
115+
"Ref": "ApiF70053CD"
116+
},
117+
"/",
118+
{
119+
"Ref": "ApiDeploymentStageprod3EB9684E"
120+
},
121+
"/POST/"
122+
]
123+
]
124+
}
125+
}
126+
},
127+
"ApiPOSTApiPermissionTestRestApiStreamStackApi1C847828POST8120A27F": {
128+
"Type": "AWS::Lambda::Permission",
129+
"Properties": {
130+
"Action": "lambda:InvokeFunction",
131+
"FunctionName": {
132+
"Fn::GetAtt": [
133+
"myfn8C66D016",
134+
"Arn"
135+
]
136+
},
137+
"Principal": "apigateway.amazonaws.com",
138+
"SourceArn": {
139+
"Fn::Join": [
140+
"",
141+
[
142+
"arn:",
143+
{
144+
"Ref": "AWS::Partition"
145+
},
146+
":execute-api:",
147+
{
148+
"Ref": "AWS::Region"
149+
},
150+
":",
151+
{
152+
"Ref": "AWS::AccountId"
153+
},
154+
":",
155+
{
156+
"Ref": "ApiF70053CD"
157+
},
158+
"/test-invoke-stage/POST/"
159+
]
160+
]
161+
}
162+
}
163+
},
164+
"ApiPOST9384DEBA": {
165+
"Type": "AWS::ApiGateway::Method",
166+
"Properties": {
167+
"AuthorizationType": "NONE",
168+
"HttpMethod": "POST",
169+
"Integration": {
170+
"IntegrationHttpMethod": "POST",
171+
"ResponseTransferMode": "STREAM",
172+
"Type": "AWS_PROXY",
173+
"Uri": {
174+
"Fn::Join": [
175+
"",
176+
[
177+
"arn:",
178+
{
179+
"Ref": "AWS::Partition"
180+
},
181+
":apigateway:",
182+
{
183+
"Ref": "AWS::Region"
184+
},
185+
":lambda:path/2021-11-15/functions/",
186+
{
187+
"Fn::GetAtt": [
188+
"myfn8C66D016",
189+
"Arn"
190+
]
191+
},
192+
"/response-streaming-invocations"
193+
]
194+
]
195+
}
196+
},
197+
"ResourceId": {
198+
"Fn::GetAtt": [
199+
"ApiF70053CD",
200+
"RootResourceId"
201+
]
202+
},
203+
"RestApiId": {
204+
"Ref": "ApiF70053CD"
205+
}
206+
}
207+
}
208+
},
209+
"Outputs": {
210+
"ApiEndpoint4F160690": {
211+
"Value": {
212+
"Fn::Join": [
213+
"",
214+
[
215+
"https://",
216+
{
217+
"Ref": "ApiF70053CD"
218+
},
219+
".execute-api.",
220+
{
221+
"Ref": "AWS::Region"
222+
},
223+
".",
224+
{
225+
"Ref": "AWS::URLSuffix"
226+
},
227+
"/",
228+
{
229+
"Ref": "ApiDeploymentStageprod3EB9684E"
230+
},
231+
"/"
232+
]
233+
]
234+
}
235+
},
236+
"ExportsOutputRefApiF70053CD5653BA4D": {
237+
"Value": {
238+
"Ref": "ApiF70053CD"
239+
},
240+
"Export": {
241+
"Name": "RestApiStreamStack:ExportsOutputRefApiF70053CD5653BA4D"
242+
}
243+
},
244+
"ExportsOutputRefApiDeploymentStageprod3EB9684E9290AA51": {
245+
"Value": {
246+
"Ref": "ApiDeploymentStageprod3EB9684E"
247+
},
248+
"Export": {
249+
"Name": "RestApiStreamStack:ExportsOutputRefApiDeploymentStageprod3EB9684E9290AA51"
250+
}
251+
}
252+
},
253+
"Parameters": {
254+
"BootstrapVersion": {
255+
"Type": "AWS::SSM::Parameter::Value<String>",
256+
"Default": "/cdk-bootstrap/hnb659fds/version",
257+
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
258+
}
259+
},
260+
"Rules": {
261+
"CheckBootstrapVersion": {
262+
"Assertions": [
263+
{
264+
"Assert": {
265+
"Fn::Not": [
266+
{
267+
"Fn::Contains": [
268+
[
269+
"1",
270+
"2",
271+
"3",
272+
"4",
273+
"5"
274+
],
275+
{
276+
"Ref": "BootstrapVersion"
277+
}
278+
]
279+
}
280+
]
281+
},
282+
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
283+
}
284+
]
285+
}
286+
}
287+
}

0 commit comments

Comments
 (0)