Skip to content

Commit 9a01514

Browse files
author
Michael Brewer
committed
refactor: create exceptions and content_types
1 parent 6f78317 commit 9a01514

File tree

5 files changed

+73
-66
lines changed

5 files changed

+73
-66
lines changed

aws_lambda_powertools/event_handler/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Event handler decorators for common Lambda events
33
"""
44

5+
from .api_gateway import ApiGatewayResolver
56
from .appsync import AppSyncResolver
67

7-
__all__ = ["AppSyncResolver"]
8+
__all__ = ["AppSyncResolver", "ApiGatewayResolver"]

aws_lambda_powertools/event_handler/api_gateway.py

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,57 +7,14 @@
77
from http import HTTPStatus
88
from typing import Any, Callable, Dict, List, Optional, Set, Union
99

10+
from aws_lambda_powertools.event_handler import content_types
11+
from aws_lambda_powertools.event_handler.exceptions import ServiceError
1012
from aws_lambda_powertools.shared.json_encoder import Encoder
1113
from aws_lambda_powertools.utilities.data_classes import ALBEvent, APIGatewayProxyEvent, APIGatewayProxyEventV2
1214
from aws_lambda_powertools.utilities.data_classes.common import BaseProxyEvent
1315
from aws_lambda_powertools.utilities.typing import LambdaContext
1416

1517
logger = logging.getLogger(__name__)
16-
APPLICATION_JSON = "application/json"
17-
18-
19-
class ServiceError(Exception):
20-
"""Service Error"""
21-
22-
def __init__(self, status_code: int, msg: str):
23-
"""
24-
Parameters
25-
----------
26-
status_code: int
27-
Http status code
28-
msg: str
29-
Error message
30-
"""
31-
self.status_code = status_code
32-
self.msg = msg
33-
34-
35-
class BadRequestError(ServiceError):
36-
"""Bad Request Error"""
37-
38-
def __init__(self, msg: str):
39-
super().__init__(HTTPStatus.BAD_REQUEST.value, msg)
40-
41-
42-
class UnauthorizedError(ServiceError):
43-
"""Unauthorized Error"""
44-
45-
def __init__(self, msg: str):
46-
super().__init__(HTTPStatus.UNAUTHORIZED.value, msg)
47-
48-
49-
class NotFoundError(ServiceError):
50-
"""Not Found Error"""
51-
52-
def __init__(self, msg: str = "Not found"):
53-
super().__init__(HTTPStatus.NOT_FOUND.value, msg)
54-
55-
56-
class InternalServerError(ServiceError):
57-
"""Internal Server Error"""
58-
59-
def __init__(self, message: str):
60-
super().__init__(HTTPStatus.INTERNAL_SERVER_ERROR.value, message)
6118

6219

6320
class ProxyEventType(Enum):
@@ -513,7 +470,7 @@ def _not_found(self, method: str) -> ResponseBuilder:
513470
return ResponseBuilder(
514471
Response(
515472
status_code=HTTPStatus.NOT_FOUND.value,
516-
content_type=APPLICATION_JSON,
473+
content_type=content_types.APPLICATION_JSON,
517474
headers=headers,
518475
body=self._json_dump({"statusCode": HTTPStatus.NOT_FOUND.value, "message": "Not found"}),
519476
)
@@ -527,7 +484,7 @@ def _call_route(self, route: Route, args: Dict[str, str]) -> ResponseBuilder:
527484
return ResponseBuilder(
528485
Response(
529486
status_code=e.status_code,
530-
content_type=APPLICATION_JSON,
487+
content_type=content_types.APPLICATION_JSON,
531488
body=self._json_dump({"statusCode": e.status_code, "message": e.msg}),
532489
),
533490
route,
@@ -548,7 +505,7 @@ def _to_response(self, result: Union[Dict, Response]) -> Response:
548505
logger.debug("Simple response detected, serializing return before constructing final response")
549506
return Response(
550507
status_code=200,
551-
content_type=APPLICATION_JSON,
508+
content_type=content_types.APPLICATION_JSON,
552509
body=self._json_dump(result),
553510
)
554511

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
APPLICATION_JSON = "application/json"
2+
PLAIN_TEXT = "plain/text"
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from http import HTTPStatus
2+
3+
4+
class ServiceError(Exception):
5+
"""Service Error"""
6+
7+
def __init__(self, status_code: int, msg: str):
8+
"""
9+
Parameters
10+
----------
11+
status_code: int
12+
Http status code
13+
msg: str
14+
Error message
15+
"""
16+
self.status_code = status_code
17+
self.msg = msg
18+
19+
20+
class BadRequestError(ServiceError):
21+
"""Bad Request Error"""
22+
23+
def __init__(self, msg: str):
24+
super().__init__(HTTPStatus.BAD_REQUEST.value, msg)
25+
26+
27+
class UnauthorizedError(ServiceError):
28+
"""Unauthorized Error"""
29+
30+
def __init__(self, msg: str):
31+
super().__init__(HTTPStatus.UNAUTHORIZED.value, msg)
32+
33+
34+
class NotFoundError(ServiceError):
35+
"""Not Found Error"""
36+
37+
def __init__(self, msg: str = "Not found"):
38+
super().__init__(HTTPStatus.NOT_FOUND.value, msg)
39+
40+
41+
class InternalServerError(ServiceError):
42+
"""Internal Server Error"""
43+
44+
def __init__(self, message: str):
45+
super().__init__(HTTPStatus.INTERNAL_SERVER_ERROR.value, message)

tests/functional/event_handler/test_api_gateway.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,18 @@
55
from pathlib import Path
66
from typing import Dict
77

8+
from aws_lambda_powertools.event_handler import content_types
89
from aws_lambda_powertools.event_handler.api_gateway import (
9-
APPLICATION_JSON,
1010
ApiGatewayResolver,
11-
BadRequestError,
1211
CORSConfig,
13-
InternalServerError,
14-
NotFoundError,
1512
ProxyEventType,
1613
Response,
1714
ResponseBuilder,
15+
)
16+
from aws_lambda_powertools.event_handler.exceptions import (
17+
BadRequestError,
18+
InternalServerError,
19+
NotFoundError,
1820
ServiceError,
1921
UnauthorizedError,
2022
)
@@ -60,15 +62,15 @@ def test_api_gateway_v1():
6062
def get_lambda() -> Response:
6163
assert isinstance(app.current_event, APIGatewayProxyEvent)
6264
assert app.lambda_context == {}
63-
return Response(200, APPLICATION_JSON, json.dumps({"foo": "value"}))
65+
return Response(200, content_types.APPLICATION_JSON, json.dumps({"foo": "value"}))
6466

6567
# WHEN calling the event handler
6668
result = app(LOAD_GW_EVENT, {})
6769

6870
# THEN process event correctly
6971
# AND set the current_event type as APIGatewayProxyEvent
7072
assert result["statusCode"] == 200
71-
assert result["headers"]["Content-Type"] == APPLICATION_JSON
73+
assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON
7274

7375

7476
def test_api_gateway():
@@ -98,15 +100,15 @@ def test_api_gateway_v2():
98100
def my_path() -> Response:
99101
assert isinstance(app.current_event, APIGatewayProxyEventV2)
100102
post_data = app.current_event.json_body
101-
return Response(200, "plain/text", post_data["username"])
103+
return Response(200, content_types.PLAIN_TEXT, post_data["username"])
102104

103105
# WHEN calling the event handler
104106
result = app(load_event("apiGatewayProxyV2Event.json"), {})
105107

106108
# THEN process event correctly
107109
# AND set the current_event type as APIGatewayProxyEventV2
108110
assert result["statusCode"] == 200
109-
assert result["headers"]["Content-Type"] == "plain/text"
111+
assert result["headers"]["Content-Type"] == content_types.PLAIN_TEXT
110112
assert result["body"] == "tom"
111113

112114

@@ -220,7 +222,7 @@ def test_compress():
220222

221223
@app.get("/my/request", compress=True)
222224
def with_compression() -> Response:
223-
return Response(200, APPLICATION_JSON, expected_value)
225+
return Response(200, content_types.APPLICATION_JSON, expected_value)
224226

225227
def handler(event, context):
226228
return app.resolve(event, context)
@@ -266,7 +268,7 @@ def test_compress_no_accept_encoding():
266268

267269
@app.get("/my/path", compress=True)
268270
def return_text() -> Response:
269-
return Response(200, "text/plain", expected_value)
271+
return Response(200, content_types.PLAIN_TEXT, expected_value)
270272

271273
# WHEN calling the event handler
272274
result = app({"path": "/my/path", "httpMethod": "GET", "headers": {}}, None)
@@ -332,7 +334,7 @@ def rest_func() -> Dict:
332334

333335
# THEN automatically process this as a json rest api response
334336
assert result["statusCode"] == 200
335-
assert result["headers"]["Content-Type"] == APPLICATION_JSON
337+
assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON
336338
expected_str = json.dumps(expected_dict, separators=(",", ":"), indent=None, cls=Encoder)
337339
assert result["body"] == expected_str
338340

@@ -387,7 +389,7 @@ def another_one():
387389
# THEN routes by default return the custom cors headers
388390
assert "headers" in result
389391
headers = result["headers"]
390-
assert headers["Content-Type"] == APPLICATION_JSON
392+
assert headers["Content-Type"] == content_types.APPLICATION_JSON
391393
assert headers["Access-Control-Allow-Origin"] == cors_config.allow_origin
392394
expected_allows_headers = ",".join(sorted(set(allow_header + cors_config._REQUIRED_HEADERS)))
393395
assert headers["Access-Control-Allow-Headers"] == expected_allows_headers
@@ -516,7 +518,7 @@ def bad_request_error():
516518
# THEN return the bad request error response
517519
# AND status code equals 400
518520
assert result["statusCode"] == 400
519-
assert result["headers"]["Content-Type"] == APPLICATION_JSON
521+
assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON
520522
expected = {"statusCode": 400, "message": "Missing required parameter"}
521523
assert result["body"] == json_dump(expected)
522524

@@ -531,7 +533,7 @@ def unauthorized_error():
531533
# THEN return the unauthorized error response
532534
# AND status code equals 401
533535
assert result["statusCode"] == 401
534-
assert result["headers"]["Content-Type"] == APPLICATION_JSON
536+
assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON
535537
expected = {"statusCode": 401, "message": "Unauthorized"}
536538
assert result["body"] == json_dump(expected)
537539

@@ -546,7 +548,7 @@ def not_found_error():
546548
# THEN return the not found error response
547549
# AND status code equals 404
548550
assert result["statusCode"] == 404
549-
assert result["headers"]["Content-Type"] == APPLICATION_JSON
551+
assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON
550552
expected = {"statusCode": 404, "message": "Not found"}
551553
assert result["body"] == json_dump(expected)
552554

@@ -561,7 +563,7 @@ def internal_server_error():
561563
# THEN return the internal server error response
562564
# AND status code equals 500
563565
assert result["statusCode"] == 500
564-
assert result["headers"]["Content-Type"] == APPLICATION_JSON
566+
assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON
565567
expected = {"statusCode": 500, "message": "Internal server error"}
566568
assert result["body"] == json_dump(expected)
567569

@@ -576,7 +578,7 @@ def service_error():
576578
# THEN return the service error response
577579
# AND status code equals 502
578580
assert result["statusCode"] == 502
579-
assert result["headers"]["Content-Type"] == APPLICATION_JSON
581+
assert result["headers"]["Content-Type"] == content_types.APPLICATION_JSON
580582
assert "Access-Control-Allow-Origin" in result["headers"]
581583
expected = {"statusCode": 502, "message": "Something went wrong!"}
582584
assert result["body"] == json_dump(expected)

0 commit comments

Comments
 (0)