5
5
from pathlib import Path
6
6
from typing import Dict
7
7
8
+ from aws_lambda_powertools .event_handler import content_types
8
9
from aws_lambda_powertools .event_handler .api_gateway import (
9
10
ApiGatewayResolver ,
10
11
CORSConfig ,
11
12
ProxyEventType ,
12
13
Response ,
13
14
ResponseBuilder ,
14
15
)
16
+ from aws_lambda_powertools .event_handler .exceptions import (
17
+ BadRequestError ,
18
+ InternalServerError ,
19
+ NotFoundError ,
20
+ ServiceError ,
21
+ UnauthorizedError ,
22
+ )
15
23
from aws_lambda_powertools .shared .json_encoder import Encoder
16
24
from aws_lambda_powertools .utilities .data_classes import ALBEvent , APIGatewayProxyEvent , APIGatewayProxyEventV2
17
25
from tests .functional .utils import load_event
@@ -24,7 +32,6 @@ def read_media(file_name: str) -> bytes:
24
32
25
33
LOAD_GW_EVENT = load_event ("apiGatewayProxyEvent.json" )
26
34
TEXT_HTML = "text/html"
27
- APPLICATION_JSON = "application/json"
28
35
29
36
30
37
def test_alb_event ():
@@ -55,15 +62,15 @@ def test_api_gateway_v1():
55
62
def get_lambda () -> Response :
56
63
assert isinstance (app .current_event , APIGatewayProxyEvent )
57
64
assert app .lambda_context == {}
58
- return Response (200 , APPLICATION_JSON , json .dumps ({"foo" : "value" }))
65
+ return Response (200 , content_types . APPLICATION_JSON , json .dumps ({"foo" : "value" }))
59
66
60
67
# WHEN calling the event handler
61
68
result = app (LOAD_GW_EVENT , {})
62
69
63
70
# THEN process event correctly
64
71
# AND set the current_event type as APIGatewayProxyEvent
65
72
assert result ["statusCode" ] == 200
66
- assert result ["headers" ]["Content-Type" ] == APPLICATION_JSON
73
+ assert result ["headers" ]["Content-Type" ] == content_types . APPLICATION_JSON
67
74
68
75
69
76
def test_api_gateway ():
@@ -93,15 +100,15 @@ def test_api_gateway_v2():
93
100
def my_path () -> Response :
94
101
assert isinstance (app .current_event , APIGatewayProxyEventV2 )
95
102
post_data = app .current_event .json_body
96
- return Response (200 , "plain/text" , post_data ["username" ])
103
+ return Response (200 , content_types . PLAIN_TEXT , post_data ["username" ])
97
104
98
105
# WHEN calling the event handler
99
106
result = app (load_event ("apiGatewayProxyV2Event.json" ), {})
100
107
101
108
# THEN process event correctly
102
109
# AND set the current_event type as APIGatewayProxyEventV2
103
110
assert result ["statusCode" ] == 200
104
- assert result ["headers" ]["Content-Type" ] == "plain/text"
111
+ assert result ["headers" ]["Content-Type" ] == content_types . PLAIN_TEXT
105
112
assert result ["body" ] == "tom"
106
113
107
114
@@ -215,7 +222,7 @@ def test_compress():
215
222
216
223
@app .get ("/my/request" , compress = True )
217
224
def with_compression () -> Response :
218
- return Response (200 , APPLICATION_JSON , expected_value )
225
+ return Response (200 , content_types . APPLICATION_JSON , expected_value )
219
226
220
227
def handler (event , context ):
221
228
return app .resolve (event , context )
@@ -261,7 +268,7 @@ def test_compress_no_accept_encoding():
261
268
262
269
@app .get ("/my/path" , compress = True )
263
270
def return_text () -> Response :
264
- return Response (200 , "text/plain" , expected_value )
271
+ return Response (200 , content_types . PLAIN_TEXT , expected_value )
265
272
266
273
# WHEN calling the event handler
267
274
result = app ({"path" : "/my/path" , "httpMethod" : "GET" , "headers" : {}}, None )
@@ -327,7 +334,7 @@ def rest_func() -> Dict:
327
334
328
335
# THEN automatically process this as a json rest api response
329
336
assert result ["statusCode" ] == 200
330
- assert result ["headers" ]["Content-Type" ] == APPLICATION_JSON
337
+ assert result ["headers" ]["Content-Type" ] == content_types . APPLICATION_JSON
331
338
expected_str = json .dumps (expected_dict , separators = ("," , ":" ), indent = None , cls = Encoder )
332
339
assert result ["body" ] == expected_str
333
340
@@ -382,7 +389,7 @@ def another_one():
382
389
# THEN routes by default return the custom cors headers
383
390
assert "headers" in result
384
391
headers = result ["headers" ]
385
- assert headers ["Content-Type" ] == APPLICATION_JSON
392
+ assert headers ["Content-Type" ] == content_types . APPLICATION_JSON
386
393
assert headers ["Access-Control-Allow-Origin" ] == cors_config .allow_origin
387
394
expected_allows_headers = "," .join (sorted (set (allow_header + cors_config ._REQUIRED_HEADERS )))
388
395
assert headers ["Access-Control-Allow-Headers" ] == expected_allows_headers
@@ -429,6 +436,7 @@ def test_no_matches_with_cors():
429
436
# AND cors headers are returned
430
437
assert result ["statusCode" ] == 404
431
438
assert "Access-Control-Allow-Origin" in result ["headers" ]
439
+ assert "Not found" in result ["body" ]
432
440
433
441
434
442
def test_cors_preflight ():
@@ -490,3 +498,87 @@ def custom_method():
490
498
assert headers ["Content-Type" ] == TEXT_HTML
491
499
assert "Access-Control-Allow-Origin" in result ["headers" ]
492
500
assert headers ["Access-Control-Allow-Methods" ] == "CUSTOM"
501
+
502
+
503
+ def test_service_error_responses ():
504
+ # SCENARIO handling different kind of service errors being raised
505
+ app = ApiGatewayResolver (cors = CORSConfig ())
506
+
507
+ def json_dump (obj ):
508
+ return json .dumps (obj , separators = ("," , ":" ))
509
+
510
+ # GIVEN an BadRequestError
511
+ @app .get (rule = "/bad-request-error" , cors = False )
512
+ def bad_request_error ():
513
+ raise BadRequestError ("Missing required parameter" )
514
+
515
+ # WHEN calling the handler
516
+ # AND path is /bad-request-error
517
+ result = app ({"path" : "/bad-request-error" , "httpMethod" : "GET" }, None )
518
+ # THEN return the bad request error response
519
+ # AND status code equals 400
520
+ assert result ["statusCode" ] == 400
521
+ assert result ["headers" ]["Content-Type" ] == content_types .APPLICATION_JSON
522
+ expected = {"statusCode" : 400 , "message" : "Missing required parameter" }
523
+ assert result ["body" ] == json_dump (expected )
524
+
525
+ # GIVEN an UnauthorizedError
526
+ @app .get (rule = "/unauthorized-error" , cors = False )
527
+ def unauthorized_error ():
528
+ raise UnauthorizedError ("Unauthorized" )
529
+
530
+ # WHEN calling the handler
531
+ # AND path is /unauthorized-error
532
+ result = app ({"path" : "/unauthorized-error" , "httpMethod" : "GET" }, None )
533
+ # THEN return the unauthorized error response
534
+ # AND status code equals 401
535
+ assert result ["statusCode" ] == 401
536
+ assert result ["headers" ]["Content-Type" ] == content_types .APPLICATION_JSON
537
+ expected = {"statusCode" : 401 , "message" : "Unauthorized" }
538
+ assert result ["body" ] == json_dump (expected )
539
+
540
+ # GIVEN an NotFoundError
541
+ @app .get (rule = "/not-found-error" , cors = False )
542
+ def not_found_error ():
543
+ raise NotFoundError
544
+
545
+ # WHEN calling the handler
546
+ # AND path is /not-found-error
547
+ result = app ({"path" : "/not-found-error" , "httpMethod" : "GET" }, None )
548
+ # THEN return the not found error response
549
+ # AND status code equals 404
550
+ assert result ["statusCode" ] == 404
551
+ assert result ["headers" ]["Content-Type" ] == content_types .APPLICATION_JSON
552
+ expected = {"statusCode" : 404 , "message" : "Not found" }
553
+ assert result ["body" ] == json_dump (expected )
554
+
555
+ # GIVEN an InternalServerError
556
+ @app .get (rule = "/internal-server-error" , cors = False )
557
+ def internal_server_error ():
558
+ raise InternalServerError ("Internal server error" )
559
+
560
+ # WHEN calling the handler
561
+ # AND path is /internal-server-error
562
+ result = app ({"path" : "/internal-server-error" , "httpMethod" : "GET" }, None )
563
+ # THEN return the internal server error response
564
+ # AND status code equals 500
565
+ assert result ["statusCode" ] == 500
566
+ assert result ["headers" ]["Content-Type" ] == content_types .APPLICATION_JSON
567
+ expected = {"statusCode" : 500 , "message" : "Internal server error" }
568
+ assert result ["body" ] == json_dump (expected )
569
+
570
+ # GIVEN an ServiceError with a custom status code
571
+ @app .get (rule = "/service-error" , cors = True )
572
+ def service_error ():
573
+ raise ServiceError (502 , "Something went wrong!" )
574
+
575
+ # WHEN calling the handler
576
+ # AND path is /service-error
577
+ result = app ({"path" : "/service-error" , "httpMethod" : "GET" }, None )
578
+ # THEN return the service error response
579
+ # AND status code equals 502
580
+ assert result ["statusCode" ] == 502
581
+ assert result ["headers" ]["Content-Type" ] == content_types .APPLICATION_JSON
582
+ assert "Access-Control-Allow-Origin" in result ["headers" ]
583
+ expected = {"statusCode" : 502 , "message" : "Something went wrong!" }
584
+ assert result ["body" ] == json_dump (expected )
0 commit comments