Skip to content

Commit ccf0f19

Browse files
committed
Fix dynamic route param handling and add pretty logs
1 parent 5546d0c commit ccf0f19

5 files changed

Lines changed: 63 additions & 6 deletions

File tree

acai_aws/apigateway/request.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def __init__(self, event, lambda_context=None, timeout=None):
1414
self.__timeout = timeout
1515
self.__body = event['body'] if event.get('body') is not None else {}
1616
self.__route = event['path'] if event.get('path') is not None else ''
17-
self.__path_params = event['pathParameters'] if event.get('pathParameters') is not None else ''
17+
self.__path_params = event['pathParameters'] if isinstance(event.get('pathParameters'), dict) else {}
1818
self.__request_context = event['requestContext'] if event.get('requestContext') is not None else {}
1919
self.__domain = event.get('requestContext', {}).get('domainName', '')
2020
self.__stage = event.get('requestContext', {}).get('stage', '')
@@ -152,6 +152,8 @@ def path_params(self):
152152
@path_params.setter
153153
def path_params(self, path_params):
154154
key, value = path_params
155+
if not isinstance(self.__path_params, dict):
156+
self.__path_params = {}
155157
self.__path_params[key] = value
156158

157159
@property

acai_aws/apigateway/resolver/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from urllib.parse import unquote
2+
13
from acai_aws.apigateway.resolver.cache import ResolverCache
24
from acai_aws.apigateway.endpoint import Endpoint
35
from acai_aws.apigateway.exception import ApiException
@@ -99,4 +101,4 @@ def __apply_dynamic_route_params(self, request, required_route_parts):
99101
message='no route found; endpoint does not have proper variables in required_route'
100102
)
101103
dynamic_name = variable_name.strip('{').strip('}')
102-
request.path_params = dynamic_name, self.__resolver.dynamic_parts[part]
104+
request.path_params = dynamic_name, unquote(self.__resolver.dynamic_parts[part])

acai_aws/common/logger/common_logger.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ def __init__(self):
1919
'WARN': 2,
2020
'ERROR': 3
2121
}
22-
if self.__format not in ['JSON', 'INLINE']:
23-
raise ValueError(f'LOG_FORMAT ENV must be either `JSON` or `INLINE`, recieved: {self.__format}')
22+
if self.__format not in ['JSON', 'PRETTY', 'INLINE']:
23+
raise ValueError(f'LOG_FORMAT ENV must be either `JSON`, `PRETTY`, or `INLINE`, recieved: {self.__format}')
2424

2525
def log(self, **kwargs):
2626
default_log = {'level': kwargs.get('level', 'INFO'), 'log': kwargs.get('log', {})}
2727
if self.__should_log(default_log['level']) and self.__format == 'JSON':
2828
self.__log_json(**kwargs)
29+
elif self.__should_log(default_log['level']) and self.__format == 'PRETTY':
30+
self.__log_json(pretty=True, **kwargs)
2931
elif self.__should_log(default_log['level']) and self.__format == 'INLINE':
3032
self.__log_inline(**kwargs)
3133

@@ -40,13 +42,13 @@ def __should_log(self, level):
4042
log_level_setting = self.log_levels[self.__log_level]
4143
return current_log_level >= log_level_setting
4244

43-
def __log_json(self, **kwargs):
45+
def __log_json(self, pretty=False, **kwargs):
4446
print(self.__json.encode({
4547
'level': kwargs['level'],
4648
'time': datetime.datetime.now(datetime.timezone.utc).isoformat(),
4749
'trace': [trace.strip() for trace in self.__get_traceback().split('\n') if trace],
4850
'log': kwargs['log']
49-
}, indent=4))
51+
}, indent=4 if pretty else None))
5052

5153
def __log_inline(self, **kwargs):
5254
timestamp = datetime.datetime.now(datetime.timezone.utc).isoformat()

tests/acai_aws/apigateway/router/test_directory_router.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,45 @@ def test_basic_directory_routing_works_with_single_dynamic_route(self):
7070
self.assertDictEqual(self.expected_open_headers, result['headers'])
7171
self.assertDictEqual({'directory_user_id': {'proxy': 'user', 'user_id': '1'}}, json_dict_response)
7272

73+
def test_basic_directory_routing_works_with_single_dynamic_route_when_path_parameters_is_none(self):
74+
dynamic_event = self.mock_request.get_dynamic_event(
75+
headers={'x-api-key': 'some-key'},
76+
path='unit-test/v1/user/auth0|12312490845',
77+
proxy='user',
78+
method='get'
79+
)
80+
dynamic_event['pathParameters'] = None
81+
router = Router(
82+
base_path=self.base_path,
83+
handlers=self.handler_path,
84+
output_error=True
85+
)
86+
result = router.route(dynamic_event, None)
87+
json_dict_response = json.loads(result['body'])
88+
self.assertFalse(result['isBase64Encoded'])
89+
self.assertEqual(200, result['statusCode'])
90+
self.assertDictEqual(self.expected_open_headers, result['headers'])
91+
self.assertDictEqual({'directory_user_id': {'user_id': 'auth0|12312490845'}}, json_dict_response)
92+
93+
def test_basic_directory_routing_decodes_encoded_dynamic_route_values(self):
94+
dynamic_event = self.mock_request.get_dynamic_event(
95+
headers={'x-api-key': 'some-key'},
96+
path='unit-test/v1/user/auth0%7C12312490845',
97+
proxy='user',
98+
method='get'
99+
)
100+
dynamic_event['pathParameters'] = {}
101+
router = Router(
102+
base_path=self.base_path,
103+
handlers=self.handler_path
104+
)
105+
result = router.route(dynamic_event, None)
106+
json_dict_response = json.loads(result['body'])
107+
self.assertFalse(result['isBase64Encoded'])
108+
self.assertEqual(200, result['statusCode'])
109+
self.assertDictEqual(self.expected_open_headers, result['headers'])
110+
self.assertDictEqual({'directory_user_id': {'user_id': 'auth0|12312490845'}}, json_dict_response)
111+
73112
def test_basic_directory_routing_works_with_double_dynamic_route(self):
74113
dynamic_event = self.mock_request.get_dynamic_event(
75114
headers={'x-api-key': 'some-key'},

tests/acai_aws/common/test_logger.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ def test_logger_json_output(self):
6767
with redirect_stdout(buffer):
6868
logger.log(level='WARN', log={'json': True})
6969
log_output = buffer.getvalue().strip()
70+
self.assertNotIn('\n', log_output)
71+
parsed = json.loads(log_output)
72+
self.assertEqual('WARN', parsed['level'])
73+
self.assertEqual({'json': True}, parsed['log'])
74+
75+
@mock.patch.dict(os.environ, {'RUN_MODE': 'SEE-LOGS', 'LOG_STAGE_VARIABLE': 'STAGE', 'STAGE': 'local', 'LOG_FORMAT': 'PRETTY'})
76+
def test_logger_pretty_output(self):
77+
buffer = io.StringIO()
78+
with redirect_stdout(buffer):
79+
logger.log(level='WARN', log={'json': True})
80+
log_output = buffer.getvalue().strip()
81+
self.assertIn('\n', log_output)
7082
parsed = json.loads(log_output)
7183
self.assertEqual('WARN', parsed['level'])
7284
self.assertEqual({'json': True}, parsed['log'])

0 commit comments

Comments
 (0)