Skip to content

Commit 287e424

Browse files
author
Shreya
authored
fix(HttpApi): add path parameters if not present (#1510)
2 parents fbc216c + 946c991 commit 287e424

File tree

10 files changed

+473
-204
lines changed

10 files changed

+473
-204
lines changed

samtranslator/model/eventsources/push.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,12 @@ def _add_openapi_integration(self, api, function, manage_swagger=False):
10701070
self._add_auth_to_openapi_integration(api, editor)
10711071
if self.TimeoutInMillis:
10721072
editor.add_timeout_to_method(api=api, path=self.Path, method_name=self.Method, timeout=self.TimeoutInMillis)
1073+
path_parameters = re.findall("{(.*?)}", self.Path)
1074+
if path_parameters:
1075+
editor.add_path_parameters_to_method(
1076+
api=api, path=self.Path, method_name=self.Method, path_parameters=path_parameters
1077+
)
1078+
10731079
api["DefinitionBody"] = editor.openapi
10741080

10751081
def _add_auth_to_openapi_integration(self, api, editor):

samtranslator/open_api/open_api.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,38 @@ def add_timeout_to_method(self, api, path, method_name, timeout):
257257
if self.method_definition_has_integration(method_definition):
258258
method_definition[self._X_APIGW_INTEGRATION]["timeoutInMillis"] = timeout
259259

260+
def add_path_parameters_to_method(self, api, path, method_name, path_parameters):
261+
"""
262+
Adds path parameters to this path + method
263+
264+
:param dict api: Reference to the related Api's properties as defined in the template.
265+
:param string path: Path name
266+
:param string method_name: Method name
267+
:param list path_parameters: list of strings of path parameters
268+
"""
269+
normalized_method_name = self._normalize_method_name(method_name)
270+
for method_definition in self.get_method_contents(self.get_path(path)[normalized_method_name]):
271+
# create path parameter list
272+
# add it here if it doesn't exist, merge with existing otherwise.
273+
method_definition.setdefault("parameters", [])
274+
for param in path_parameters:
275+
# find an existing parameter with this name if it exists
276+
existing_parameter = next(
277+
(
278+
existing_parameter
279+
for existing_parameter in method_definition.get("parameters", [])
280+
if existing_parameter.get("name") == param
281+
),
282+
None,
283+
)
284+
if existing_parameter:
285+
# overwrite parameter values for existing path parameter
286+
existing_parameter["in"] = "path"
287+
existing_parameter["required"] = True
288+
else:
289+
parameter = {"name": param, "in": "path", "required": True}
290+
method_definition.get("parameters").append(parameter)
291+
260292
def add_authorizers_security_definitions(self, authorizers):
261293
"""
262294
Add Authorizer definitions to the securityDefinitions part of Swagger.

tests/translator/input/http_api_existing_openapi.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ Resources:
3535
Properties:
3636
ApiId: !Ref MyApi
3737
TimeoutInMillis: !Ref Timeout
38+
PathParametersExisting:
39+
Type: HttpApi
40+
Properties:
41+
ApiId: !Ref MyApi
42+
Path: /get/{something}/with/{params}
43+
Method: GET
3844
MyApi:
3945
Type: AWS::Serverless::HttpApi
4046
Properties:
@@ -65,6 +71,13 @@ Resources:
6571
- OpenIdAuth:
6672
- scope3
6773
responses: {}
74+
"/get/{something}/with/{params}":
75+
get:
76+
parameters:
77+
-
78+
name: something
79+
in: path
80+
responses: {}
6881
"/integration":
6982
post:
7083
x-amazon-apigateway-integration:

tests/translator/input/implicit_http_api.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@ Resources:
2828
Properties:
2929
Path: /basic2
3030
Method: post
31+
PathParameters:
32+
Type: HttpApi
33+
Properties:
34+
Path: /get/{something}/with/{params}
35+
Method: POST

tests/translator/output/aws-cn/http_api_existing_openapi.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,31 @@
105105
}
106106
},
107107
"paths": {
108+
"/get/{something}/with/{params}": {
109+
"get": {
110+
"x-amazon-apigateway-integration": {
111+
"httpMethod": "POST",
112+
"type": "aws_proxy",
113+
"uri": {
114+
"Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations"
115+
},
116+
"payloadFormatVersion": "1.0"
117+
},
118+
"responses": {},
119+
"parameters": [
120+
{
121+
"required": true,
122+
"name": "something",
123+
"in": "path"
124+
},
125+
{
126+
"required": true,
127+
"name": "params",
128+
"in": "path"
129+
}
130+
]
131+
}
132+
},
108133
"/basic": {
109134
"post": {
110135
"x-amazon-apigateway-integration": {

tests/translator/output/aws-cn/implicit_http_api.json

Lines changed: 114 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@
1616
"HttpApiFunctionRole": {
1717
"Type": "AWS::IAM::Role",
1818
"Properties": {
19-
"ManagedPolicyArns": [
20-
"arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
21-
"arn:aws-cn:iam::aws:policy/AmazonDynamoDBFullAccess"
22-
],
2319
"AssumeRolePolicyDocument": {
2420
"Version": "2012-10-17",
2521
"Statement": [
@@ -36,6 +32,10 @@
3632
}
3733
]
3834
},
35+
"ManagedPolicyArns": [
36+
"arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
37+
"arn:aws-cn:iam::aws:policy/AmazonDynamoDBFullAccess"
38+
],
3939
"Tags": [
4040
{
4141
"Value": "SAM",
@@ -47,10 +47,6 @@
4747
"HttpApiFunction2Role": {
4848
"Type": "AWS::IAM::Role",
4949
"Properties": {
50-
"ManagedPolicyArns": [
51-
"arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
52-
"arn:aws-cn:iam::aws:policy/AmazonDynamoDBFullAccess"
53-
],
5450
"AssumeRolePolicyDocument": {
5551
"Version": "2012-10-17",
5652
"Statement": [
@@ -67,6 +63,77 @@
6763
}
6864
]
6965
},
66+
"ManagedPolicyArns": [
67+
"arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
68+
"arn:aws-cn:iam::aws:policy/AmazonDynamoDBFullAccess"
69+
],
70+
"Tags": [
71+
{
72+
"Value": "SAM",
73+
"Key": "lambda:createdBy"
74+
}
75+
]
76+
}
77+
},
78+
"HttpApiFunction": {
79+
"Type": "AWS::Lambda::Function",
80+
"Properties": {
81+
"Handler": "index.restapi",
82+
"Code": {
83+
"S3Bucket": "sam-demo-bucket",
84+
"S3Key": "todo_list.zip"
85+
},
86+
"Role": {
87+
"Fn::GetAtt": [
88+
"HttpApiFunctionRole",
89+
"Arn"
90+
]
91+
},
92+
"Runtime": "nodejs12.x",
93+
"Tags": [
94+
{
95+
"Value": "SAM",
96+
"Key": "lambda:createdBy"
97+
}
98+
]
99+
}
100+
},
101+
"HttpApiFunctionSimpleCasePermission": {
102+
"Type": "AWS::Lambda::Permission",
103+
"Properties": {
104+
"Action": "lambda:InvokeFunction",
105+
"Principal": "apigateway.amazonaws.com",
106+
"FunctionName": {
107+
"Ref": "HttpApiFunction"
108+
},
109+
"SourceArn": {
110+
"Fn::Sub": [
111+
"arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*",
112+
{
113+
"__Stage__": "*",
114+
"__ApiId__": {
115+
"Ref": "ServerlessHttpApi"
116+
}
117+
}
118+
]
119+
}
120+
}
121+
},
122+
"HttpApiFunction2": {
123+
"Type": "AWS::Lambda::Function",
124+
"Properties": {
125+
"Handler": "index.restapi",
126+
"Code": {
127+
"S3Bucket": "sam-demo-bucket",
128+
"S3Key": "todo_list.zip"
129+
},
130+
"Role": {
131+
"Fn::GetAtt": [
132+
"HttpApiFunction2Role",
133+
"Arn"
134+
]
135+
},
136+
"Runtime": "nodejs12.x",
70137
"Tags": [
71138
{
72139
"Value": "SAM",
@@ -85,12 +152,6 @@
85152
"Ref": "AWS::StackName"
86153
}
87154
},
88-
"tags": [
89-
{
90-
"name": "httpapi:createdBy",
91-
"x-amazon-apigateway-tag-value": "SAM"
92-
}
93-
],
94155
"paths": {
95156
"/basic2": {
96157
"post": {
@@ -105,17 +166,29 @@
105166
"responses": {}
106167
}
107168
},
108-
"/basic": {
169+
"/get/{something}/with/{params}": {
109170
"post": {
110171
"x-amazon-apigateway-integration": {
111172
"httpMethod": "POST",
112173
"type": "aws_proxy",
113174
"uri": {
114-
"Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations"
175+
"Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction2.Arn}/invocations"
115176
},
116177
"payloadFormatVersion": "1.0"
117178
},
118-
"responses": {}
179+
"responses": {},
180+
"parameters": [
181+
{
182+
"required": true,
183+
"name": "something",
184+
"in": "path"
185+
},
186+
{
187+
"required": true,
188+
"name": "params",
189+
"in": "path"
190+
}
191+
]
119192
}
120193
},
121194
"$default": {
@@ -131,23 +204,42 @@
131204
"isDefaultRoute": true,
132205
"responses": {}
133206
}
207+
},
208+
"/basic": {
209+
"post": {
210+
"x-amazon-apigateway-integration": {
211+
"httpMethod": "POST",
212+
"type": "aws_proxy",
213+
"uri": {
214+
"Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations"
215+
},
216+
"payloadFormatVersion": "1.0"
217+
},
218+
"responses": {}
219+
}
134220
}
135221
},
136-
"openapi": "3.0.1"
222+
"openapi": "3.0.1",
223+
"tags": [
224+
{
225+
"name": "httpapi:createdBy",
226+
"x-amazon-apigateway-tag-value": "SAM"
227+
}
228+
]
137229
}
138230
}
139231
},
140-
"HttpApiFunctionSimpleCasePermission": {
232+
"HttpApiFunction2PathParametersPermission": {
141233
"Type": "AWS::Lambda::Permission",
142234
"Properties": {
143235
"Action": "lambda:InvokeFunction",
144236
"Principal": "apigateway.amazonaws.com",
145237
"FunctionName": {
146-
"Ref": "HttpApiFunction"
238+
"Ref": "HttpApiFunction2"
147239
},
148240
"SourceArn": {
149241
"Fn::Sub": [
150-
"arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/*",
242+
"arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/POST/get/*/with/*",
151243
{
152244
"__Stage__": "*",
153245
"__ApiId__": {
@@ -158,52 +250,6 @@
158250
}
159251
}
160252
},
161-
"HttpApiFunction2": {
162-
"Type": "AWS::Lambda::Function",
163-
"Properties": {
164-
"Handler": "index.restapi",
165-
"Code": {
166-
"S3Bucket": "sam-demo-bucket",
167-
"S3Key": "todo_list.zip"
168-
},
169-
"Role": {
170-
"Fn::GetAtt": [
171-
"HttpApiFunction2Role",
172-
"Arn"
173-
]
174-
},
175-
"Runtime": "nodejs12.x",
176-
"Tags": [
177-
{
178-
"Value": "SAM",
179-
"Key": "lambda:createdBy"
180-
}
181-
]
182-
}
183-
},
184-
"HttpApiFunction": {
185-
"Type": "AWS::Lambda::Function",
186-
"Properties": {
187-
"Handler": "index.restapi",
188-
"Code": {
189-
"S3Bucket": "sam-demo-bucket",
190-
"S3Key": "todo_list.zip"
191-
},
192-
"Role": {
193-
"Fn::GetAtt": [
194-
"HttpApiFunctionRole",
195-
"Arn"
196-
]
197-
},
198-
"Runtime": "nodejs12.x",
199-
"Tags": [
200-
{
201-
"Value": "SAM",
202-
"Key": "lambda:createdBy"
203-
}
204-
]
205-
}
206-
},
207253
"HttpApiFunction2Basic2Permission": {
208254
"Type": "AWS::Lambda::Permission",
209255
"Properties": {
@@ -226,4 +272,4 @@
226272
}
227273
}
228274
}
229-
}
275+
}

0 commit comments

Comments
 (0)