import json import logging import os import urllib.parse from typing import Optional, Any from aws_lambda_powertools import Tracer from libs.common_tools import DecimalEncoder url_suffix = os.environ.get("URL_SUFFIX") logger = logging.getLogger(__name__) logger.setLevel(os.environ.get('LOG_LEVEL') or logging.ERROR) tracer = Tracer() esd_version = os.environ.get("ESD_VERSION") x_api_version = esd_version.split('-')[0].replace('v', '') class HttpStatusCode: OK = 200 Created = 201 Accepted = 202 NoContent: int = 204 BadRequest = 400 Unauthorized = 401 Forbidden = 403 NotFound = 404 InternalServerError = 500 # Mapping status codes to descriptions http_status_descriptions = { HttpStatusCode.OK: "OK", HttpStatusCode.Created: "Created", HttpStatusCode.Accepted: "Accepted", HttpStatusCode.NoContent: "No Content", HttpStatusCode.BadRequest: "Bad Request", HttpStatusCode.Unauthorized: "Unauthorized", HttpStatusCode.Forbidden: "Forbidden", HttpStatusCode.NotFound: "Not Found", HttpStatusCode.InternalServerError: "Internal Server Error" } class StatusCode: def __init__(self, code): self.code = code self.description = http_status_descriptions.get(code, "Unknown Status Code") def __str__(self): return f"Status Code: {self.code} - {self.description}" @tracer.capture_method def response(status_code: int, data=None, message: str = None, headers: Optional[dict[str, Any]] = None, decimal=None): payload = { 'isBase64Encoded': False, 'statusCode': status_code, } if headers is None: headers = { 'Content-Type': 'application/json', } else: headers['Content-Type'] = 'application/json' headers['x-api-version'] = x_api_version headers['Access-Control-Allow-Origin'] = '*' headers['Access-Control-Allow-Headers'] = '*' headers['Access-Control-Allow-Methods'] = '*' headers['Access-Control-Allow-Credentials'] = True payload['headers'] = headers body = { 'statusCode': status_code, 'debug': get_debug(), } if data: body['data'] = data if message: body['message'] = message if decimal: payload['body'] = json.dumps(body, cls=DecimalEncoder) else: payload['body'] = json.dumps(body) logger.info("Lambda Response Payload:") logger.info(payload['body']) return payload def get_debug(): aws_lambda_log_group_name = os.environ.get('AWS_LAMBDA_LOG_GROUP_NAME') aws_lambda_function_name = os.environ.get('AWS_LAMBDA_FUNCTION_NAME') aws_lambda_log_stream_name = os.environ.get('AWS_LAMBDA_LOG_STREAM_NAME') _x_amzn_trace_id = os.environ.get('_X_AMZN_TRACE_ID') region = os.environ.get('AWS_DEFAULT_REGION') log_group_name = urllib.parse.quote(aws_lambda_log_group_name, safe='') log_stream_name = urllib.parse.quote(aws_lambda_log_stream_name, safe='') if url_suffix.endswith('.cn'): console_url_suffix = "amazonaws.cn" else: console_url_suffix = "aws.amazon.com" log_url = (f"https://{region}.console.{console_url_suffix}/cloudwatch/home?region={region}" f"#logsV2:log-groups/log-group/{log_group_name}/log-events/{log_stream_name}") function_url = (f"https://{region}.console.{console_url_suffix}/lambda/home?region={region}" f"#/functions/{aws_lambda_function_name}") trace_url = None if _x_amzn_trace_id: trace_id = _x_amzn_trace_id.split(';')[0].split('=')[1] trace_url = (f"https://{region}.console.{console_url_suffix}/cloudwatch/home?region={region}" f"#xray:traces/{trace_id}") return { 'function_url': function_url, 'log_url': log_url, 'trace_url': trace_url, } def ok(data=None, message: str = http_status_descriptions[HttpStatusCode.OK], headers: Optional[dict[str, Any]] = None, decimal=None ): return response(HttpStatusCode.OK, data, message, headers, decimal) def created(data=None, message: str = http_status_descriptions[HttpStatusCode.Created], headers: Optional[dict[str, Any]] = None, decimal=None ): return response(HttpStatusCode.Created, data, message, headers, decimal) def accepted(data=None, message: str = http_status_descriptions[HttpStatusCode.Accepted], headers: Optional[dict[str, Any]] = None, decimal=None ): return response(HttpStatusCode.Accepted, data, message, headers, decimal) def no_content(data=None, message: str = http_status_descriptions[HttpStatusCode.NoContent], headers: Optional[dict[str, Any]] = None, decimal=None ): return response(HttpStatusCode.NoContent, data, message, headers, decimal) def bad_request(data=None, message: str = http_status_descriptions[HttpStatusCode.BadRequest], headers: Optional[dict[str, Any]] = None, decimal=None ): return response(HttpStatusCode.BadRequest, data, message, headers, decimal) def unauthorized(data=None, message: str = http_status_descriptions[HttpStatusCode.Unauthorized], headers: Optional[dict[str, Any]] = None, decimal=None ): return response(HttpStatusCode.Unauthorized, data, message, headers, decimal) def forbidden(data=None, message: str = http_status_descriptions[HttpStatusCode.Forbidden], headers: Optional[dict[str, Any]] = None, decimal=None ): return response(HttpStatusCode.Forbidden, data, message, headers, decimal) def not_found(data=None, message: str = http_status_descriptions[HttpStatusCode.NotFound], headers: Optional[dict[str, Any]] = None, decimal=None ): return response(HttpStatusCode.NotFound, data, message, headers, decimal) def internal_server_error(data=None, message: str = http_status_descriptions[HttpStatusCode.InternalServerError], headers: Optional[dict[str, Any]] = None, decimal=None): return response(HttpStatusCode.InternalServerError, data, message, headers, decimal)