From b2c66e1aae0a77d95c32a32bbdc9b10df3ac37e5 Mon Sep 17 00:00:00 2001 From: Keeton Hodgson Date: Tue, 3 Mar 2020 15:27:26 -0800 Subject: [PATCH 1/4] Add route settings --- samtranslator/model/api/http_api_generator.py | 5 ++- samtranslator/model/apigatewayv2.py | 1 + samtranslator/model/eventsources/push.py | 1 + samtranslator/model/sam_resources.py | 2 + .../plugins/api/implicit_api_plugin.py | 13 ++++++- .../plugins/api/implicit_http_api_plugin.py | 38 +++++++++++++++++++ .../plugins/api/implicit_rest_api_plugin.py | 6 +++ 7 files changed, 64 insertions(+), 2 deletions(-) diff --git a/samtranslator/model/api/http_api_generator.py b/samtranslator/model/api/http_api_generator.py index 5a96ea6e7f..349c321815 100644 --- a/samtranslator/model/api/http_api_generator.py +++ b/samtranslator/model/api/http_api_generator.py @@ -26,6 +26,7 @@ def __init__( tags=None, auth=None, access_log_settings=None, + route_settings=None, resource_attributes=None, passthrough_resource_attributes=None, ): @@ -54,6 +55,7 @@ def __init__( self.auth = auth self.tags = tags self.access_log_settings = access_log_settings + self.route_settings = route_settings self.resource_attributes = resource_attributes self.passthrough_resource_attributes = passthrough_resource_attributes @@ -237,7 +239,7 @@ def _construct_stage(self): """ # If there are no special configurations, don't create a stage and use the default - if not self.stage_name and not self.stage_variables and not self.access_log_settings: + if not self.stage_name and not self.stage_variables and not self.access_log_settings and not route_settings: return # If StageName is some intrinsic function, then don't prefix the Stage's logical ID @@ -256,6 +258,7 @@ def _construct_stage(self): stage.StageVariables = self.stage_variables stage.AccessLogSettings = self.access_log_settings stage.AutoDeploy = True + stage.RouteSettings = self.route_settings return stage diff --git a/samtranslator/model/apigatewayv2.py b/samtranslator/model/apigatewayv2.py index 93f0fdec6d..4263758f5d 100644 --- a/samtranslator/model/apigatewayv2.py +++ b/samtranslator/model/apigatewayv2.py @@ -24,6 +24,7 @@ class ApiGatewayV2Stage(Resource): property_types = { "AccessLogSettings": PropertyType(False, is_type(dict)), "DefaultRouteSettings": PropertyType(False, is_type(dict)), + "RouteSettings": PropertyType(False, is_type(dict)), "ClientCertificateId": PropertyType(False, is_str()), "Description": PropertyType(False, is_str()), "ApiId": PropertyType(True, is_str()), diff --git a/samtranslator/model/eventsources/push.py b/samtranslator/model/eventsources/push.py index 944153bf76..e2bd338766 100644 --- a/samtranslator/model/eventsources/push.py +++ b/samtranslator/model/eventsources/push.py @@ -938,6 +938,7 @@ class HttpApi(PushEventSource): "Stage": PropertyType(False, is_str()), "Auth": PropertyType(False, is_type(dict)), "TimeoutInMillis": PropertyType(False, is_type(int)), + "RouteSettings": PropertyType(False, is_type(dict)), } def resources_to_link(self, resources): diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index bec70ba569..bee50f080b 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -855,6 +855,7 @@ class SamHttpApi(SamResourceMacro): "Cors": PropertyType(False, one_of(is_str(), is_type(dict))), "AccessLogSettings": PropertyType(False, is_type(dict)), "Auth": PropertyType(False, is_type(dict)), + "RouteSettings": PropertyType(False, is_type(dict)), } referable_properties = {"Stage": ApiGatewayV2Stage.resource_type} @@ -879,6 +880,7 @@ def to_cloudformation(self, **kwargs): tags=self.Tags, auth=self.Auth, access_log_settings=self.AccessLogSettings, + route_settings=self.RouteSettings, resource_attributes=self.resource_attributes, passthrough_resource_attributes=self.get_passthrough_resource_attributes(), ) diff --git a/samtranslator/plugins/api/implicit_api_plugin.py b/samtranslator/plugins/api/implicit_api_plugin.py index 8d8895e645..0ca4c5b9ae 100644 --- a/samtranslator/plugins/api/implicit_api_plugin.py +++ b/samtranslator/plugins/api/implicit_api_plugin.py @@ -162,7 +162,10 @@ def _add_api_to_swagger(self, event_id, event_properties, template): if isinstance(api_id, dict) or not template.get(api_id): raise InvalidEventException( event_id, - "RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource " "in same template", + self.api_id_property + + " must be a valid reference to an " + + self._get_api_resource_type_name + + " resource in same template", ) # Make sure Swagger is valid @@ -343,3 +346,11 @@ def _generate_implicit_api_resource(self): raise NotImplementedError( "Method _setup_api_properties() must be implemented in a " "subclass of ImplicitApiPlugin" ) + + def _get_api_resource_type_name(self): + """ + Returns the type of API resource + """ + raise NotImplementedError( + "Method _setup_api_properties() must be implemented in a " "subclass of ImplicitApiPlugin" + ) diff --git a/samtranslator/plugins/api/implicit_http_api_plugin.py b/samtranslator/plugins/api/implicit_http_api_plugin.py index 2e53190361..bc693c2b63 100644 --- a/samtranslator/plugins/api/implicit_http_api_plugin.py +++ b/samtranslator/plugins/api/implicit_http_api_plugin.py @@ -1,5 +1,6 @@ import six +from samtranslator.model.intrinsics import make_conditional from samtranslator.model.naming import GeneratedLogicalId from samtranslator.plugins.api.implicit_api_plugin import ImplicitApiPlugin from samtranslator.public.open_api import OpenApiEditor @@ -88,6 +89,8 @@ def _process_api_events(self, function, api_events, template, condition=None): method_conditions[method] = condition self._add_api_to_swagger(logicalId, event_properties, template) + if "RouteSettings" in event_properties: + self._add_route_settings_to_api(logicalId, event_properties, template, condition) api_events[logicalId] = event # We could have made changes to the Events structure. Write it back to function @@ -116,6 +119,41 @@ def _get_api_definition_from_editor(self, editor): """ return editor.openapi + def _get_api_resource_type_name(self): + """ + Returns the type of API resource + """ + return "AWS::Serverless::HttpApi" + + def _add_route_settings_to_api(self, event_id, event_properties, template, condition): + """ + Adds the API path/method from the given event to the Swagger JSON of Serverless::Api resource this event + refers to. + + :param string event_id: LogicalId of the event + :param dict event_properties: Properties of the event + :param SamTemplate template: SAM Template to search for Serverless::Api resources + """ + + # Need to grab the AWS::Serverless::Api resource for this API event and update its Swagger definition + api_id = self._get_api_id(event_properties) + + # Make sure Swagger is valid + resource = template.get(api_id) + + path = event_properties["Path"] + method = event_properties["Method"] + + # CONDITIONS!!!!!!!!!!!!!!!! + api_route_settings = resource.properties.get("RouteSettings", {}) + if condition: + event_route_settings = {path: make_conditional(condition, event_properties.get("RouteSettings", {}))} + else: + event_route_settings = {path: event_properties.get("RouteSettings", {})} + api_route_settings.update(event_route_settings) + resource.set("RouteSettings", api_route_settings) + template.set(api_id, resource) + class ImplicitHttpApiResource(SamResource): """ diff --git a/samtranslator/plugins/api/implicit_rest_api_plugin.py b/samtranslator/plugins/api/implicit_rest_api_plugin.py index ece4980fd0..3a6461928c 100644 --- a/samtranslator/plugins/api/implicit_rest_api_plugin.py +++ b/samtranslator/plugins/api/implicit_rest_api_plugin.py @@ -115,6 +115,12 @@ def _get_api_definition_from_editor(self, editor): """ return editor.swagger + def _get_api_resource_type_name(self): + """ + Returns the type of API resource + """ + return "AWS::Serverless::Api" + class ImplicitApiResource(SamResource): """ From d100288bf26246d3cb36d9ddabf67bfea874c572 Mon Sep 17 00:00:00 2001 From: Keeton Hodgson Date: Wed, 4 Mar 2020 10:57:59 -0800 Subject: [PATCH 2/4] Continue working on route settings --- .../plugins/api/implicit_api_plugin.py | 6 ++-- .../plugins/api/implicit_http_api_plugin.py | 28 +++++++++++-------- samtranslator/plugins/globals/globals.py | 1 + .../output/error_api_invalid_restapiid.json | 4 +-- .../error_http_api_event_invalid_api.json | 4 +-- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/samtranslator/plugins/api/implicit_api_plugin.py b/samtranslator/plugins/api/implicit_api_plugin.py index 0ca4c5b9ae..89da2c9647 100644 --- a/samtranslator/plugins/api/implicit_api_plugin.py +++ b/samtranslator/plugins/api/implicit_api_plugin.py @@ -163,9 +163,9 @@ def _add_api_to_swagger(self, event_id, event_properties, template): raise InvalidEventException( event_id, self.api_id_property - + " must be a valid reference to an " - + self._get_api_resource_type_name - + " resource in same template", + + " must be a valid reference to an '" + + self._get_api_resource_type_name() + + "' resource in same template.", ) # Make sure Swagger is valid diff --git a/samtranslator/plugins/api/implicit_http_api_plugin.py b/samtranslator/plugins/api/implicit_http_api_plugin.py index bc693c2b63..454698c067 100644 --- a/samtranslator/plugins/api/implicit_http_api_plugin.py +++ b/samtranslator/plugins/api/implicit_http_api_plugin.py @@ -127,31 +127,35 @@ def _get_api_resource_type_name(self): def _add_route_settings_to_api(self, event_id, event_properties, template, condition): """ - Adds the API path/method from the given event to the Swagger JSON of Serverless::Api resource this event - refers to. + Adds the RouteSettings for this path/method from the given event to the RouteSettings configuration + on the AWS::Serverless::HttpApi that this refers to. :param string event_id: LogicalId of the event :param dict event_properties: Properties of the event - :param SamTemplate template: SAM Template to search for Serverless::Api resources + :param SamTemplate template: SAM Template to search for Serverless::HttpApi resources + :param string condition: Condition on this HttpApi event (if any) """ - # Need to grab the AWS::Serverless::Api resource for this API event and update its Swagger definition api_id = self._get_api_id(event_properties) - - # Make sure Swagger is valid resource = template.get(api_id) path = event_properties["Path"] method = event_properties["Method"] - # CONDITIONS!!!!!!!!!!!!!!!! + # Route should be in format "METHOD /path" or just "/path" if the ANY method is used + route = "{} {}".format(method.upper(), path) + if method == OpenApiEditor._X_ANY_METHOD: + route = path + + # Handle Resource-level conditions if necessary api_route_settings = resource.properties.get("RouteSettings", {}) + event_route_settings = event_properties.get("RouteSettings", {}) if condition: - event_route_settings = {path: make_conditional(condition, event_properties.get("RouteSettings", {}))} - else: - event_route_settings = {path: event_properties.get("RouteSettings", {})} - api_route_settings.update(event_route_settings) - resource.set("RouteSettings", api_route_settings) + event_route_settings = make_conditional(condition, event_properties.get("RouteSettings", {})) + + # Merge event-level and api-level RouteSettings properties + api_route_settings.setdefault(route, {}) + api_route_settings[route].update(event_route_settings) template.set(api_id, resource) diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index e3cb4683b5..41afb4e137 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -72,6 +72,7 @@ class Globals(object): "CorsConfiguration", "DefaultRouteSettings", "Domain", + "RouteSettings", ], SamResourceType.SimpleTable.value: ["SSESpecification"], } diff --git a/tests/translator/output/error_api_invalid_restapiid.json b/tests/translator/output/error_api_invalid_restapiid.json index 58e049a957..aa4c86aa1d 100644 --- a/tests/translator/output/error_api_invalid_restapiid.json +++ b/tests/translator/output/error_api_invalid_restapiid.json @@ -1,8 +1,8 @@ { "errors": [ { - "errorMessage": "Resource with id [FunctionWithNonExistentApiReference] is invalid. Event with id [GetHtml] is invalid. RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource in same template" + "errorMessage": "Resource with id [FunctionWithNonExistentApiReference] is invalid. Event with id [GetHtml] is invalid. RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource in same template." } ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [FunctionWithNonExistentApiReference] is invalid. Event with id [GetHtml] is invalid. RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource in same template" + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [FunctionWithNonExistentApiReference] is invalid. Event with id [GetHtml] is invalid. RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource in same template." } \ No newline at end of file diff --git a/tests/translator/output/error_http_api_event_invalid_api.json b/tests/translator/output/error_http_api_event_invalid_api.json index d979bb8bf3..acbe70f0ee 100644 --- a/tests/translator/output/error_http_api_event_invalid_api.json +++ b/tests/translator/output/error_http_api_event_invalid_api.json @@ -1,8 +1,8 @@ { "errors": [ { - "errorMessage": "Resource with id [HttpApiFunction] is invalid. Event with id [Api] is invalid. RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource in same template" + "errorMessage": "Resource with id [HttpApiFunction] is invalid. Event with id [Api] is invalid. ApiId must be a valid reference to an 'AWS::Serverless::HttpApi' resource in same template." } ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [HttpApiFunction] is invalid. Event with id [Api] is invalid. RestApiId must be a valid reference to an 'AWS::Serverless::Api' resource in same template" + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. Resource with id [HttpApiFunction] is invalid. Event with id [Api] is invalid. ApiId must be a valid reference to an 'AWS::Serverless::HttpApi' resource in same template." } \ No newline at end of file From b548e46215d37481b485e3972be28565e147d0e4 Mon Sep 17 00:00:00 2001 From: Keeton Hodgson Date: Wed, 4 Mar 2020 12:28:55 -0800 Subject: [PATCH 3/4] Add tests for route settings --- .../plugins/api/implicit_http_api_plugin.py | 1 + .../input/http_api_explicit_stage.yaml | 13 +++++ ...mplicit_http_api_with_many_conditions.yaml | 7 +++ .../aws-cn/http_api_explicit_stage.json | 40 ++++++++------ ...mplicit_http_api_with_many_conditions.json | 42 +++++++++++---- .../aws-us-gov/http_api_explicit_stage.json | 53 +++++++++++-------- ...mplicit_http_api_with_many_conditions.json | 42 +++++++++++---- .../output/http_api_explicit_stage.json | 52 ++++++++++-------- ...mplicit_http_api_with_many_conditions.json | 42 +++++++++++---- 9 files changed, 204 insertions(+), 88 deletions(-) diff --git a/samtranslator/plugins/api/implicit_http_api_plugin.py b/samtranslator/plugins/api/implicit_http_api_plugin.py index 454698c067..3f8849dbc1 100644 --- a/samtranslator/plugins/api/implicit_http_api_plugin.py +++ b/samtranslator/plugins/api/implicit_http_api_plugin.py @@ -156,6 +156,7 @@ def _add_route_settings_to_api(self, event_id, event_properties, template, condi # Merge event-level and api-level RouteSettings properties api_route_settings.setdefault(route, {}) api_route_settings[route].update(event_route_settings) + resource.properties["RouteSettings"] = api_route_settings template.set(api_id, resource) diff --git a/tests/translator/input/http_api_explicit_stage.yaml b/tests/translator/input/http_api_explicit_stage.yaml index 36bca92b86..33a5f15047 100644 --- a/tests/translator/input/http_api_explicit_stage.yaml +++ b/tests/translator/input/http_api_explicit_stage.yaml @@ -2,6 +2,12 @@ Parameters: CorsParam: Type: String Default: True +Globals: + HttpApi: + RouteSettings: + "$default": + DataTraceEnabled: True + ThrottlingBurstLimit: 100 Resources: HttpApiFunction: Type: AWS::Serverless::Function @@ -14,10 +20,17 @@ Resources: Type: HttpApi Properties: ApiId: !Ref MyApi + RouteSettings: + ThrottlingBurstLimit: 300 + LoggingLevel: INFO MyApi: Type: AWS::Serverless::HttpApi Properties: StageName: Prod + RouteSettings: + "$default": + ThrottlingBurstLimit: 200 + ThrottlingRateLimit: 0.7 AccessLogSettings: DestinationArn: arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName Format: $context.requestId diff --git a/tests/translator/input/implicit_http_api_with_many_conditions.yaml b/tests/translator/input/implicit_http_api_with_many_conditions.yaml index 2fcda10e25..47dad4bd63 100644 --- a/tests/translator/input/implicit_http_api_with_many_conditions.yaml +++ b/tests/translator/input/implicit_http_api_with_many_conditions.yaml @@ -48,6 +48,9 @@ Conditions: - false Globals: HttpApi: + RouteSettings: + "GET /sub": + ThrottlingBurstLimit: 100 Auth: Authorizers: oauth2: @@ -73,6 +76,8 @@ Resources: HttpApiEvent: Type: HttpApi Properties: + RouteSettings: + ThrottlingBurstLimit: 200 Path: /sub Method: get helloworld1099: @@ -89,6 +94,8 @@ Resources: HttpApiEvent: Type: HttpApi Properties: + RouteSettings: + ThrottlingBurstLimit: 200 Auth: Authorizer: oauth2 HttpApiEvent2: diff --git a/tests/translator/output/aws-cn/http_api_explicit_stage.json b/tests/translator/output/aws-cn/http_api_explicit_stage.json index 13f444fb41..1865807fc3 100644 --- a/tests/translator/output/aws-cn/http_api_explicit_stage.json +++ b/tests/translator/output/aws-cn/http_api_explicit_stage.json @@ -1,10 +1,10 @@ { "Parameters": { "CorsParam": { - "Default": true, + "Default": true, "Type": "String" } - }, + }, "Resources": { "HttpApiFunctionSimpleCasePermission": { "Type": "AWS::Lambda::Permission", @@ -41,7 +41,7 @@ "Arn" ] }, - "Runtime": "nodejs12.x", + "Runtime": "nodejs12.x", "Tags": [ { "Value": "SAM", @@ -53,23 +53,28 @@ "MyApiProdStage": { "Type": "AWS::ApiGatewayV2::Stage", "Properties": { + "AutoDeploy": true, "ApiId": { "Ref": "MyApi" }, - "AutoDeploy": true, - "StageName": "Prod", + "StageName": "Prod", "AccessLogSettings": { - "DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName", + "DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName", "Format": "$context.requestId" + }, + "RouteSettings": { + "$default": { + "ThrottlingRateLimit": 0.7, + "DataTraceEnabled": true, + "ThrottlingBurstLimit": 300, + "LoggingLevel": "INFO" + } } } }, "HttpApiFunctionRole": { "Type": "AWS::IAM::Role", "Properties": { - "ManagedPolicyArns": [ - "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -86,6 +91,9 @@ } ] }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], "Tags": [ { "Value": "SAM", @@ -103,12 +111,7 @@ "title": { "Ref": "AWS::StackName" } - }, - "x-amazon-apigateway-cors": { - "allowOrigins": [ - "*" - ] - }, + }, "paths": { "$default": { "x-amazon-apigateway-any-method": { @@ -125,6 +128,11 @@ } } }, + "x-amazon-apigateway-cors": { + "allowOrigins": [ + "*" + ] + }, "openapi": "3.0.1", "tags": [ { @@ -136,4 +144,4 @@ } } } -} +} \ No newline at end of file diff --git a/tests/translator/output/aws-cn/implicit_http_api_with_many_conditions.json b/tests/translator/output/aws-cn/implicit_http_api_with_many_conditions.json index 519cb8083a..f2891303cc 100644 --- a/tests/translator/output/aws-cn/implicit_http_api_with_many_conditions.json +++ b/tests/translator/output/aws-cn/implicit_http_api_with_many_conditions.json @@ -199,12 +199,6 @@ "Ref": "AWS::StackName" } }, - "tags": [ - { - "name": "httpapi:createdBy", - "x-amazon-apigateway-tag-value": "SAM" - } - ], "paths": { "/hello/again": { "Fn::If": [ @@ -659,6 +653,7 @@ ] } }, + "openapi": "3.0.1", "components": { "securitySchemes": { "oauth2": { @@ -676,7 +671,12 @@ } } }, - "openapi": "3.0.1" + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] } }, "Condition": "ServerlessHttpApiCondition" @@ -1336,10 +1336,34 @@ "ServerlessHttpApiApiGatewayDefaultStage": { "Type": "AWS::ApiGatewayV2::Stage", "Properties": { + "AutoDeploy": true, "ApiId": { "Ref": "ServerlessHttpApi" }, - "AutoDeploy": true, + "RouteSettings": { + "GET /sub": { + "Fn::If": [ + "MyCondition", + { + "ThrottlingBurstLimit": 200 + }, + { + "Ref": "AWS::NoValue" + } + ] + }, + "$default": { + "Fn::If": [ + "Cond", + { + "ThrottlingBurstLimit": 200 + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, "StageName": "$default" }, "Condition": "ServerlessHttpApiCondition" @@ -1476,4 +1500,4 @@ "Condition": "Cond3" } } -} +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/http_api_explicit_stage.json b/tests/translator/output/aws-us-gov/http_api_explicit_stage.json index b4007733df..4448303536 100644 --- a/tests/translator/output/aws-us-gov/http_api_explicit_stage.json +++ b/tests/translator/output/aws-us-gov/http_api_explicit_stage.json @@ -1,11 +1,10 @@ { "Parameters": { "CorsParam": { - "Default": true, + "Default": true, "Type": "String" } - }, - + }, "Resources": { "HttpApiFunctionSimpleCasePermission": { "Type": "AWS::Lambda::Permission", @@ -42,7 +41,7 @@ "Arn" ] }, - "Runtime": "nodejs12.x", + "Runtime": "nodejs12.x", "Tags": [ { "Value": "SAM", @@ -54,23 +53,28 @@ "MyApiProdStage": { "Type": "AWS::ApiGatewayV2::Stage", "Properties": { + "AutoDeploy": true, "ApiId": { "Ref": "MyApi" }, - "AutoDeploy": true, - "StageName": "Prod", + "StageName": "Prod", "AccessLogSettings": { - "DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName", + "DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName", "Format": "$context.requestId" + }, + "RouteSettings": { + "$default": { + "ThrottlingRateLimit": 0.7, + "DataTraceEnabled": true, + "ThrottlingBurstLimit": 300, + "LoggingLevel": "INFO" + } } } }, "HttpApiFunctionRole": { "Type": "AWS::IAM::Role", "Properties": { - "ManagedPolicyArns": [ - "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -87,6 +91,9 @@ } ] }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], "Tags": [ { "Value": "SAM", @@ -105,17 +112,6 @@ "Ref": "AWS::StackName" } }, - "tags": [ - { - "name": "httpapi:createdBy", - "x-amazon-apigateway-tag-value": "SAM" - } - ], - "x-amazon-apigateway-cors": { - "allowOrigins": [ - "*" - ] - }, "paths": { "$default": { "x-amazon-apigateway-any-method": { @@ -132,9 +128,20 @@ } } }, - "openapi": "3.0.1" + "x-amazon-apigateway-cors": { + "allowOrigins": [ + "*" + ] + }, + "openapi": "3.0.1", + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] } } } } -} +} \ No newline at end of file diff --git a/tests/translator/output/aws-us-gov/implicit_http_api_with_many_conditions.json b/tests/translator/output/aws-us-gov/implicit_http_api_with_many_conditions.json index c5eea99b65..24c96e8334 100644 --- a/tests/translator/output/aws-us-gov/implicit_http_api_with_many_conditions.json +++ b/tests/translator/output/aws-us-gov/implicit_http_api_with_many_conditions.json @@ -199,12 +199,6 @@ "Ref": "AWS::StackName" } }, - "tags": [ - { - "name": "httpapi:createdBy", - "x-amazon-apigateway-tag-value": "SAM" - } - ], "paths": { "/hello/again": { "Fn::If": [ @@ -659,6 +653,7 @@ ] } }, + "openapi": "3.0.1", "components": { "securitySchemes": { "oauth2": { @@ -676,7 +671,12 @@ } } }, - "openapi": "3.0.1" + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] } }, "Condition": "ServerlessHttpApiCondition" @@ -1336,10 +1336,34 @@ "ServerlessHttpApiApiGatewayDefaultStage": { "Type": "AWS::ApiGatewayV2::Stage", "Properties": { + "AutoDeploy": true, "ApiId": { "Ref": "ServerlessHttpApi" }, - "AutoDeploy": true, + "RouteSettings": { + "GET /sub": { + "Fn::If": [ + "MyCondition", + { + "ThrottlingBurstLimit": 200 + }, + { + "Ref": "AWS::NoValue" + } + ] + }, + "$default": { + "Fn::If": [ + "Cond", + { + "ThrottlingBurstLimit": 200 + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, "StageName": "$default" }, "Condition": "ServerlessHttpApiCondition" @@ -1476,4 +1500,4 @@ "Condition": "Cond3" } } -} +} \ No newline at end of file diff --git a/tests/translator/output/http_api_explicit_stage.json b/tests/translator/output/http_api_explicit_stage.json index f6795577a9..f0adc81739 100644 --- a/tests/translator/output/http_api_explicit_stage.json +++ b/tests/translator/output/http_api_explicit_stage.json @@ -1,10 +1,10 @@ { "Parameters": { "CorsParam": { - "Default": true, + "Default": true, "Type": "String" } - }, + }, "Resources": { "HttpApiFunctionSimpleCasePermission": { "Type": "AWS::Lambda::Permission", @@ -41,7 +41,7 @@ "Arn" ] }, - "Runtime": "nodejs12.x", + "Runtime": "nodejs12.x", "Tags": [ { "Value": "SAM", @@ -53,23 +53,28 @@ "MyApiProdStage": { "Type": "AWS::ApiGatewayV2::Stage", "Properties": { + "AutoDeploy": true, "ApiId": { "Ref": "MyApi" }, - "AutoDeploy": true, - "StageName": "Prod", + "StageName": "Prod", "AccessLogSettings": { - "DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName", + "DestinationArn": "arn:aws:logs:us-east-1:123456789012:log-group:LogGroupName", "Format": "$context.requestId" + }, + "RouteSettings": { + "$default": { + "ThrottlingRateLimit": 0.7, + "DataTraceEnabled": true, + "ThrottlingBurstLimit": 300, + "LoggingLevel": "INFO" + } } } }, "HttpApiFunctionRole": { "Type": "AWS::IAM::Role", "Properties": { - "ManagedPolicyArns": [ - "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" - ], "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ @@ -86,6 +91,9 @@ } ] }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], "Tags": [ { "Value": "SAM", @@ -104,17 +112,6 @@ "Ref": "AWS::StackName" } }, - "tags": [ - { - "name": "httpapi:createdBy", - "x-amazon-apigateway-tag-value": "SAM" - } - ], - "x-amazon-apigateway-cors": { - "allowOrigins": [ - "*" - ] - }, "paths": { "$default": { "x-amazon-apigateway-any-method": { @@ -131,9 +128,20 @@ } } }, - "openapi": "3.0.1" + "x-amazon-apigateway-cors": { + "allowOrigins": [ + "*" + ] + }, + "openapi": "3.0.1", + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] } } } } -} +} \ No newline at end of file diff --git a/tests/translator/output/implicit_http_api_with_many_conditions.json b/tests/translator/output/implicit_http_api_with_many_conditions.json index ac14371a17..b653dc3f0e 100644 --- a/tests/translator/output/implicit_http_api_with_many_conditions.json +++ b/tests/translator/output/implicit_http_api_with_many_conditions.json @@ -199,12 +199,6 @@ "Ref": "AWS::StackName" } }, - "tags": [ - { - "name": "httpapi:createdBy", - "x-amazon-apigateway-tag-value": "SAM" - } - ], "paths": { "/hello/again": { "Fn::If": [ @@ -659,6 +653,7 @@ ] } }, + "openapi": "3.0.1", "components": { "securitySchemes": { "oauth2": { @@ -676,7 +671,12 @@ } } }, - "openapi": "3.0.1" + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] } }, "Condition": "ServerlessHttpApiCondition" @@ -1336,10 +1336,34 @@ "ServerlessHttpApiApiGatewayDefaultStage": { "Type": "AWS::ApiGatewayV2::Stage", "Properties": { + "AutoDeploy": true, "ApiId": { "Ref": "ServerlessHttpApi" }, - "AutoDeploy": true, + "RouteSettings": { + "GET /sub": { + "Fn::If": [ + "MyCondition", + { + "ThrottlingBurstLimit": 200 + }, + { + "Ref": "AWS::NoValue" + } + ] + }, + "$default": { + "Fn::If": [ + "Cond", + { + "ThrottlingBurstLimit": 200 + }, + { + "Ref": "AWS::NoValue" + } + ] + } + }, "StageName": "$default" }, "Condition": "ServerlessHttpApiCondition" @@ -1476,4 +1500,4 @@ "Condition": "Cond3" } } -} +} \ No newline at end of file From 08dfcde0764ac425ae065953193e31386b12c498 Mon Sep 17 00:00:00 2001 From: Keeton Hodgson Date: Wed, 4 Mar 2020 12:32:59 -0800 Subject: [PATCH 4/4] Add documentation --- docs/globals.rst | 1 + versions/2016-10-31.md | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/globals.rst b/docs/globals.rst index fc341f9ad8..5d1469e437 100644 --- a/docs/globals.rst +++ b/docs/globals.rst @@ -100,6 +100,7 @@ Currently, the following resources and properties are being supported: AccessLogSettings: Tags: DefaultRouteSettings: + RouteSettings: Domain: SimpleTable: diff --git a/versions/2016-10-31.md b/versions/2016-10-31.md index 4b868ee675..459c280cd8 100644 --- a/versions/2016-10-31.md +++ b/versions/2016-10-31.md @@ -283,6 +283,7 @@ Tags | Map of `string` to `string` | A map (string to string) that specifies the AccessLogSettings | [AccessLogSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-stage-accesslogsettings.html) | Settings for logging access in a stage. CorsConfiguration | `boolean` or [CorsConfiguration Object](#cors-configuration-object) | Enable CORS for all your Http APIs. Specify `true` for adding Cors with domain '*' to your Http APIs or specify a dictionary with additional [CorsConfiguration-Object](#cors-configuration-object). SAM adds `x-amazon-apigateway-cors` header in open api definition for your Http API when this property is defined. NOTE: Cors requires SAM to modify your OpenAPI definition. Hence it works only inline OpenAPI defined with `DefinitionBody`. DefaultRouteSettings | [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-stage-routesettings.html) | The default route settings for this HTTP API. +RouteSettings | [RouteSettings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apigatewayv2-stage-routesettings.html) | Per-route route settings for this HTTP API. Domain | [Domain Configuration Object](#domain-configuration-object) | Configuration settings for custom domains on API. Must contain `DomainName` and `CertificateArn` ##### Return values