Skip to content

Commit 65813fa

Browse files
authored
Add AWS::Serverless::HttpApi (#1941)
1 parent 028e251 commit 65813fa

File tree

2 files changed

+168
-2
lines changed

2 files changed

+168
-2
lines changed

tests/test_serverless.py

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
S3Event,
1818
S3Location,
1919
SimpleTable,
20+
HttpApi,
21+
HttpApiAuth,
22+
OAuth2Authorizer,
23+
HttpApiDomainConfiguration,
2024
)
2125

2226

@@ -186,7 +190,7 @@ def test_api_auth_resource_policy(self):
186190
t.add_resource(serverless_api)
187191
t.to_json()
188192

189-
def test_api_with_endpoint_configuation(self):
193+
def test_api_with_endpoint_configuration(self):
190194
serverless_api = Api(
191195
title="SomeApi",
192196
StageName="testStageName",
@@ -217,6 +221,80 @@ def test_api_with_domain(self):
217221
t.add_resource(serverless_api)
218222
t.to_json()
219223

224+
def test_http_api_definition_uri_defined(self):
225+
serverless_http_api = HttpApi(
226+
"SomeHttpApi",
227+
StageName="testHttp",
228+
DefinitionUri="s3://bucket/swagger.yml",
229+
)
230+
t = Template()
231+
t.add_resource(serverless_http_api)
232+
t.to_json()
233+
234+
def test_http_api_both_definition_uri_and_body_defined(self):
235+
serverless_http_api = HttpApi(
236+
"SomeHttpApi",
237+
StageName="testHttp",
238+
DefinitionUri="s3://bucket/swagger.yml",
239+
DefinitionBody=self.swagger,
240+
)
241+
t = Template()
242+
t.add_resource(serverless_http_api)
243+
with self.assertRaises(ValueError):
244+
t.to_json()
245+
246+
def test_http_api_definition_body(self):
247+
serverless_http_api = HttpApi(
248+
"SomeHttpApi",
249+
StageName="testHttp",
250+
DefinitionBody=self.swagger,
251+
)
252+
t = Template()
253+
t.add_resource(serverless_http_api)
254+
t.to_json()
255+
256+
def test_http_api_no_definition(self):
257+
serverless_api = HttpApi(
258+
"SomeHttpApi",
259+
StageName="testHttp",
260+
)
261+
t = Template()
262+
t.add_resource(serverless_api)
263+
t.to_json()
264+
265+
def test_http_api_authorization_scopes(self):
266+
serverless_api = HttpApi(
267+
title="SomeHttpApi",
268+
Auth=HttpApiAuth(
269+
Authorizers=OAuth2Authorizer(AuthorizationScopes=["scope1", "scope2"])
270+
),
271+
StageName="testHttpStageName",
272+
)
273+
t = Template()
274+
t.add_resource(serverless_api)
275+
t.to_json()
276+
277+
def test_http_api_with_domain(self):
278+
certificate = Parameter("certificate", Type="String")
279+
serverless_http_api = HttpApi(
280+
"SomeHttpApi",
281+
StageName="testHttp",
282+
Domain=HttpApiDomainConfiguration(
283+
BasePath=["/"],
284+
CertificateArn=Ref(certificate),
285+
DomainName=Sub("subdomain.${Zone}", Zone=ImportValue("MyZone")),
286+
EndpointConfiguration="REGIONAL",
287+
Route53=Route53(
288+
HostedZoneId=ImportValue("MyZone"),
289+
IpV6=True,
290+
),
291+
),
292+
)
293+
t = Template()
294+
t.add_parameter(certificate)
295+
t.add_resource(serverless_http_api)
296+
t.to_json()
297+
220298
def test_simple_table(self):
221299
serverless_table = SimpleTable("SomeTable")
222300
t = Template()

troposphere/serverless.py

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from . import AWSHelperFn, AWSObject, AWSProperty
99
from .apigateway import AccessLogSetting, CanarySetting, MethodSetting
10+
from .apigatewayv2 import AccessLogSettings, RouteSettings
1011
from .awslambda import (
1112
DestinationConfig,
1213
Environment,
@@ -25,6 +26,7 @@
2526
integer_range,
2627
mutually_exclusive,
2728
positive_integer,
29+
boolean,
2830
)
2931

3032
try:
@@ -335,6 +337,10 @@ def validate(self):
335337
)
336338

337339

340+
class ApiDefinition(AWSProperty):
341+
props = {"Bucket": (str, True), "Key": (str, True), "Version": (str, False)}
342+
343+
338344
class Api(AWSObject):
339345
resource_type = "AWS::Serverless::Api"
340346

@@ -347,7 +353,7 @@ class Api(AWSObject):
347353
"CanarySetting": (CanarySetting, False),
348354
"Cors": ((str, Cors), False),
349355
"DefinitionBody": (dict, False),
350-
"DefinitionUri": (str, False),
356+
"DefinitionUri": ((str, ApiDefinition), False),
351357
"Domain": (Domain, False),
352358
"EndpointConfiguration": (EndpointConfiguration, False),
353359
"MethodSettings": ([MethodSetting], False),
@@ -367,6 +373,88 @@ def validate(self):
367373
mutually_exclusive(self.__class__.__name__, self.properties, conds)
368374

369375

376+
class OAuth2Authorizer(AWSProperty):
377+
props = {
378+
"AuthorizationScopes": (list, False),
379+
"IdentitySource": (str, False),
380+
"JwtConfiguration": (dict, False),
381+
}
382+
383+
384+
class LambdaAuthorizationIdentity(AWSProperty):
385+
props = {
386+
"Context": (list, False),
387+
"Headers": (list, False),
388+
"QueryStrings": (list, False),
389+
"ReauthorizeEvery": (integer, False),
390+
"StageVariables": (list, False),
391+
}
392+
393+
394+
class LambdaAuthorizer(AWSProperty):
395+
props = {
396+
"AuthorizerPayloadFormatVersion": (str, True),
397+
"EnableSimpleResponses": (boolean, False),
398+
"FunctionArn": (str, True),
399+
"FunctionInvokeRole": (str, False),
400+
"Identity": (LambdaAuthorizationIdentity, False),
401+
}
402+
403+
404+
class HttpApiAuth(AWSProperty):
405+
props = {
406+
"Authorizers": ((OAuth2Authorizer, LambdaAuthorizer), False),
407+
"DefaultAuthorizer": (str, False),
408+
}
409+
410+
411+
class HttpApiCorsConfiguration(AWSProperty):
412+
props = {
413+
"AllowCredentials": (boolean, False),
414+
"AllowHeaders": (list, False),
415+
"AllowMethods": (list, False),
416+
"AllowOrigins": (list, False),
417+
"ExposeHeaders": (list, False),
418+
"MaxAge": (integer, False),
419+
}
420+
421+
422+
class HttpApiDefinition(ApiDefinition):
423+
pass
424+
425+
426+
class HttpApiDomainConfiguration(Domain):
427+
pass
428+
429+
430+
class HttpApi(AWSObject):
431+
resource_type = "AWS::Serverless::HttpApi"
432+
433+
props = {
434+
"AccessLogSettings": (AccessLogSettings, False),
435+
"Auth": (HttpApiAuth, False),
436+
"CorsConfiguration": ((str, HttpApiCorsConfiguration), False),
437+
"DefaultRouteSettings": (RouteSettings, False),
438+
"DefinitionBody": (dict, False),
439+
"DefinitionUri": ((str, HttpApiDefinition), False),
440+
"Description": (str, False),
441+
"DisableExecuteApiEndpoint": (boolean, False),
442+
"Domain": (HttpApiDomainConfiguration, False),
443+
"FailOnWarnings": (boolean, False),
444+
"RouteSettings": (dict, False),
445+
"StageName": (str, False),
446+
"StageVariables": (dict, False),
447+
"Tags": (dict, False),
448+
}
449+
450+
def validate(self):
451+
conds = [
452+
"DefinitionBody",
453+
"DefinitionUri",
454+
]
455+
mutually_exclusive(self.__class__.__name__, self.properties, conds)
456+
457+
370458
class PrimaryKey(AWSProperty):
371459
props = {"Name": (str, False), "Type": (primary_key_type_validator, False)}
372460

0 commit comments

Comments
 (0)