1
- from typing import Any , Dict , Optional , cast
1
+ from typing import Any , Dict , Optional , Type , cast
2
2
3
3
from samtranslator .model .intrinsics import make_conditional
4
- from samtranslator .model .naming import GeneratedLogicalId
5
4
from samtranslator .plugins .api .implicit_api_plugin import ImplicitApiPlugin
6
5
from samtranslator .public .open_api import OpenApiEditor
7
- from samtranslator .public .exceptions import InvalidEventException
8
6
from samtranslator .public .sdk .resource import SamResourceType , SamResource
9
7
from samtranslator .sdk .template import SamTemplate
10
8
from samtranslator .validator .value_validator import sam_expect
11
9
12
10
13
- class ImplicitHttpApiPlugin (ImplicitApiPlugin ):
11
+ class ImplicitHttpApiPlugin (ImplicitApiPlugin [ Type [ OpenApiEditor ]] ):
14
12
"""
15
13
This plugin provides Implicit Http API shorthand syntax in the SAM Spec.
16
14
@@ -28,26 +26,22 @@ class ImplicitHttpApiPlugin(ImplicitApiPlugin):
28
26
in OpenApi. Does **not** configure the API by any means.
29
27
"""
30
28
31
- def __init__ (self ) -> None :
32
- """
33
- Initializes the plugin
34
- """
35
- super (ImplicitHttpApiPlugin , self ).__init__ (ImplicitHttpApiPlugin .__name__ )
36
-
37
- def _setup_api_properties (self ) -> None :
38
- """
39
- Sets up properties that are distinct to this plugin
40
- """
41
- self .implicit_api_logical_id = GeneratedLogicalId .implicit_http_api ()
42
- self .implicit_api_condition = "ServerlessHttpApiCondition"
43
- self .api_event_type = "HttpApi"
44
- self .api_type = SamResourceType .HttpApi .value
45
- self .api_id_property = "ApiId"
46
- self .editor = OpenApiEditor
47
-
48
- def _process_api_events ( # type: ignore[no-untyped-def]
49
- self , function , api_events , template , condition = None , deletion_policy = None , update_replace_policy = None
50
- ):
29
+ API_ID_EVENT_PROPERTY = "ApiId"
30
+ IMPLICIT_API_LOGICAL_ID = "ServerlessHttpApi"
31
+ IMPLICIT_API_CONDITION = "ServerlessHttpApiCondition"
32
+ API_EVENT_TYPE = "HttpApi"
33
+ SERVERLESS_API_RESOURCE_TYPE = SamResourceType .HttpApi .value
34
+ EDITOR_CLASS = OpenApiEditor
35
+
36
+ def _process_api_events (
37
+ self ,
38
+ function : SamResource ,
39
+ api_events : Dict [str , Dict [str , Any ]],
40
+ template : SamTemplate ,
41
+ condition : Optional [str ] = None ,
42
+ deletion_policy : Optional [str ] = None ,
43
+ update_replace_policy : Optional [str ] = None ,
44
+ ) -> None :
51
45
"""
52
46
Actually process given HTTP API events. Iteratively adds the APIs to OpenApi JSON in the respective
53
47
AWS::Serverless::HttpApi resource from the template
@@ -58,21 +52,16 @@ def _process_api_events( # type: ignore[no-untyped-def]
58
52
:param str condition: optional; this is the condition that is on the function with the API event
59
53
"""
60
54
61
- for logicalId , event in api_events .items ():
55
+ for event_id , event in api_events .items ():
62
56
# api_events only contains HttpApi events
63
57
event_properties = event .get ("Properties" , {})
64
58
65
- if not isinstance (event_properties , dict ):
66
- raise InvalidEventException (
67
- logicalId ,
68
- "Event 'Properties' must be an Object. If you're using YAML, this may be an indentation issue." ,
69
- )
70
-
59
+ sam_expect (event_properties , event_id , "" , is_sam_event = True ).to_be_a_map ("Properties should be a map." )
71
60
if not event_properties :
72
- event ["Properties" ] = event_properties
61
+ event ["Properties" ] = event_properties # We are updating its Properties
62
+
73
63
self ._add_implicit_api_id_if_necessary (event_properties ) # type: ignore[no-untyped-call]
74
64
75
- api_id = self ._get_api_id (event_properties ) # type: ignore[no-untyped-call]
76
65
path = event_properties .get ("Path" , "" )
77
66
method = event_properties .get ("Method" , "" )
78
67
# If no path and method specified, add the $default path and ANY method
@@ -81,49 +70,20 @@ def _process_api_events( # type: ignore[no-untyped-def]
81
70
method = "x-amazon-apigateway-any-method"
82
71
event_properties ["Path" ] = path
83
72
event_properties ["Method" ] = method
84
- elif not path or not method :
85
- key = "Path" if not path else "Method"
86
- raise InvalidEventException (logicalId , "Event is missing key '{}'." .format (key ))
87
-
88
- if not isinstance (path , str ) or not isinstance (method , str ):
89
- key = "Path" if not isinstance (path , str ) else "Method"
90
- raise InvalidEventException (logicalId , "Api Event must have a String specified for '{}'." .format (key ))
91
73
92
- # !Ref is resolved by this time. If it is not a string, we can't parse/use this Api.
93
- if api_id and not isinstance (api_id , str ):
94
- raise InvalidEventException (
95
- logicalId , "Api Event's ApiId must be a string referencing an Api in the same template."
96
- )
74
+ api_id , path , method = self ._validate_api_event (event_id , event_properties )
75
+ self ._update_resource_attributes_from_api_event (
76
+ api_id , path , method , condition , deletion_policy , update_replace_policy
77
+ )
97
78
98
- api_dict_condition = self .api_conditions .setdefault (api_id , {})
99
- method_conditions = api_dict_condition .setdefault (path , {})
100
- method_conditions [method ] = condition
101
-
102
- api_dict_deletion = self .api_deletion_policies .setdefault (api_id , set ())
103
- api_dict_deletion .add (deletion_policy )
104
-
105
- api_dict_update_replace = self .api_update_replace_policies .setdefault (api_id , set ())
106
- api_dict_update_replace .add (update_replace_policy )
107
-
108
- self ._add_api_to_swagger (logicalId , event_properties , template ) # type: ignore[no-untyped-call]
79
+ self ._add_api_to_swagger (event_id , event_properties , template ) # type: ignore[no-untyped-call]
109
80
if "RouteSettings" in event_properties :
110
- self ._add_route_settings_to_api (logicalId , event_properties , template , condition )
111
- api_events [logicalId ] = event
81
+ self ._add_route_settings_to_api (event_id , event_properties , template , condition )
82
+ api_events [event_id ] = event
112
83
113
84
# We could have made changes to the Events structure. Write it back to function
114
85
function .properties ["Events" ].update (api_events )
115
86
116
- def _add_implicit_api_id_if_necessary (self , event_properties ): # type: ignore[no-untyped-def]
117
- """
118
- Events for implicit APIs will *not* have the RestApiId property. Absence of this property means this event
119
- is associated with the AWS::Serverless::Api ImplicitAPI resource.
120
- This method solidifies this assumption by adding RestApiId property to events that don't have them.
121
-
122
- :param dict event_properties: Dictionary of event properties
123
- """
124
- if "ApiId" not in event_properties :
125
- event_properties ["ApiId" ] = {"Ref" : self .implicit_api_logical_id }
126
-
127
87
def _generate_implicit_api_resource (self ) -> Dict [str , Any ]:
128
88
"""
129
89
Uses the implicit API in this file to generate an Implicit API resource
@@ -136,12 +96,6 @@ def _get_api_definition_from_editor(self, editor: OpenApiEditor) -> Dict[str, An
136
96
"""
137
97
return editor .openapi
138
98
139
- def _get_api_resource_type_name (self ) -> str :
140
- """
141
- Returns the type of API resource
142
- """
143
- return "AWS::Serverless::HttpApi"
144
-
145
99
def _add_route_settings_to_api (
146
100
self , event_id : str , event_properties : Dict [str , Any ], template : SamTemplate , condition : Optional [str ]
147
101
) -> None :
@@ -155,7 +109,7 @@ def _add_route_settings_to_api(
155
109
:param string condition: Condition on this HttpApi event (if any)
156
110
"""
157
111
158
- api_id = self ._get_api_id (event_properties ) # type: ignore[no-untyped-call]
112
+ api_id = self ._get_api_id (event_properties )
159
113
resource = cast (SamResource , template .get (api_id )) # TODO: make this not an assumption
160
114
161
115
path = event_properties ["Path" ]
0 commit comments