diff --git a/{{ cookiecutter.project_name }}/events/hello.json b/{{ cookiecutter.project_name }}/events/hello.json new file mode 100644 index 0000000..596fd56 --- /dev/null +++ b/{{ cookiecutter.project_name }}/events/hello.json @@ -0,0 +1,123 @@ +{ + "body": "hello", + "resource": "/hello", + "path": "/hello", + "httpMethod": "GET", + "isBase64Encoded": true, + "queryStringParameters": { + "foo": "bar" + }, + "multiValueQueryStringParameters": { + "foo": [ + "bar" + ] + }, + "pathParameters": { + "hello": "/hello" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "multiValueHeaders": { + "Accept": [ + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" + ], + "Accept-Encoding": [ + "gzip, deflate, sdch" + ], + "Accept-Language": [ + "en-US,en;q=0.8" + ], + "Cache-Control": [ + "max-age=0" + ], + "CloudFront-Forwarded-Proto": [ + "https" + ], + "CloudFront-Is-Desktop-Viewer": [ + "true" + ], + "CloudFront-Is-Mobile-Viewer": [ + "false" + ], + "CloudFront-Is-SmartTV-Viewer": [ + "false" + ], + "CloudFront-Is-Tablet-Viewer": [ + "false" + ], + "CloudFront-Viewer-Country": [ + "US" + ], + "Host": [ + "0123456789.execute-api.us-east-1.amazonaws.com" + ], + "Upgrade-Insecure-Requests": [ + "1" + ], + "User-Agent": [ + "Custom User Agent String" + ], + "Via": [ + "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)" + ], + "X-Amz-Cf-Id": [ + "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==" + ], + "X-Forwarded-For": [ + "127.0.0.1, 127.0.0.2" + ], + "X-Forwarded-Port": [ + "443" + ], + "X-Forwarded-Proto": [ + "https" + ] + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "Prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "25/Jul/2020:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/Prod/hello", + "resourcePath": "/hello", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } +} \ No newline at end of file diff --git a/{{ cookiecutter.project_name }}/events/hello_name.json b/{{ cookiecutter.project_name }}/events/hello_name.json new file mode 100644 index 0000000..ebd3d67 --- /dev/null +++ b/{{ cookiecutter.project_name }}/events/hello_name.json @@ -0,0 +1,109 @@ +{ + "body": "hello", + "resource": "/hello", + "path": "/hello/you", + "httpMethod": "GET", + "isBase64Encoded": true, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "multiValueHeaders": { + "Accept": [ + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" + ], + "Accept-Encoding": [ + "gzip, deflate, sdch" + ], + "Accept-Language": [ + "en-US,en;q=0.8" + ], + "Cache-Control": [ + "max-age=0" + ], + "CloudFront-Forwarded-Proto": [ + "https" + ], + "CloudFront-Is-Desktop-Viewer": [ + "true" + ], + "CloudFront-Is-Mobile-Viewer": [ + "false" + ], + "CloudFront-Is-SmartTV-Viewer": [ + "false" + ], + "CloudFront-Is-Tablet-Viewer": [ + "false" + ], + "CloudFront-Viewer-Country": [ + "US" + ], + "Host": [ + "0123456789.execute-api.us-east-1.amazonaws.com" + ], + "Upgrade-Insecure-Requests": [ + "1" + ], + "User-Agent": [ + "Custom User Agent String" + ], + "Via": [ + "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)" + ], + "X-Amz-Cf-Id": [ + "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==" + ], + "X-Forwarded-For": [ + "127.0.0.1, 127.0.0.2" + ], + "X-Forwarded-Port": [ + "443" + ], + "X-Forwarded-Proto": [ + "https" + ] + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "Prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "25/Jul/2020:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/Prod/hello/you", + "resourcePath": "/hello/you", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } +} \ No newline at end of file diff --git a/{{ cookiecutter.project_name }}/events/hello_world_event.json b/{{ cookiecutter.project_name }}/events/hello_world_event.json deleted file mode 100644 index 03a0dc0..0000000 --- a/{{ cookiecutter.project_name }}/events/hello_world_event.json +++ /dev/null @@ -1,123 +0,0 @@ -{ - "body": "hello", - "resource": "/hello", - "path": "/hello", - "httpMethod": "GET", - "isBase64Encoded": true, - "queryStringParameters": { - "foo": "bar" - }, - "multiValueQueryStringParameters": { - "foo": [ - "bar" - ] - }, - "pathParameters": { - "hello": "/hello" - }, - "stageVariables": { - "baz": "qux" - }, - "headers": { - "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", - "Accept-Encoding": "gzip, deflate, sdch", - "Accept-Language": "en-US,en;q=0.8", - "Cache-Control": "max-age=0", - "CloudFront-Forwarded-Proto": "https", - "CloudFront-Is-Desktop-Viewer": "true", - "CloudFront-Is-Mobile-Viewer": "false", - "CloudFront-Is-SmartTV-Viewer": "false", - "CloudFront-Is-Tablet-Viewer": "false", - "CloudFront-Viewer-Country": "US", - "Host": "1234567890.execute-api.us-east-1.amazonaws.com", - "Upgrade-Insecure-Requests": "1", - "User-Agent": "Custom User Agent String", - "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", - "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", - "X-Forwarded-For": "127.0.0.1, 127.0.0.2", - "X-Forwarded-Port": "443", - "X-Forwarded-Proto": "https" - }, - "multiValueHeaders": { - "Accept": [ - "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" - ], - "Accept-Encoding": [ - "gzip, deflate, sdch" - ], - "Accept-Language": [ - "en-US,en;q=0.8" - ], - "Cache-Control": [ - "max-age=0" - ], - "CloudFront-Forwarded-Proto": [ - "https" - ], - "CloudFront-Is-Desktop-Viewer": [ - "true" - ], - "CloudFront-Is-Mobile-Viewer": [ - "false" - ], - "CloudFront-Is-SmartTV-Viewer": [ - "false" - ], - "CloudFront-Is-Tablet-Viewer": [ - "false" - ], - "CloudFront-Viewer-Country": [ - "US" - ], - "Host": [ - "0123456789.execute-api.us-east-1.amazonaws.com" - ], - "Upgrade-Insecure-Requests": [ - "1" - ], - "User-Agent": [ - "Custom User Agent String" - ], - "Via": [ - "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)" - ], - "X-Amz-Cf-Id": [ - "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==" - ], - "X-Forwarded-For": [ - "127.0.0.1, 127.0.0.2" - ], - "X-Forwarded-Port": [ - "443" - ], - "X-Forwarded-Proto": [ - "https" - ] - }, - "requestContext": { - "accountId": "123456789012", - "resourceId": "123456", - "stage": "Prod", - "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", - "requestTime": "25/Jul/2020:12:34:56 +0000", - "requestTimeEpoch": 1428582896000, - "identity": { - "cognitoIdentityPoolId": null, - "accountId": null, - "cognitoIdentityId": null, - "caller": null, - "accessKey": null, - "sourceIp": "127.0.0.1", - "cognitoAuthenticationType": null, - "cognitoAuthenticationProvider": null, - "userArn": null, - "userAgent": "Custom User Agent String", - "user": null - }, - "path": "/Prod/hello", - "resourcePath": "/hello", - "httpMethod": "POST", - "apiId": "1234567890", - "protocol": "HTTP/1.1" - } -} \ No newline at end of file diff --git a/{{ cookiecutter.project_name }}/hello_world/app.py b/{{ cookiecutter.project_name }}/hello_world/app.py index aceee10..c4b1bf8 100644 --- a/{{ cookiecutter.project_name }}/hello_world/app.py +++ b/{{ cookiecutter.project_name }}/hello_world/app.py @@ -1,37 +1,38 @@ -import json -import os - -import boto3 from aws_lambda_powertools import Logger, Metrics, Tracer -from aws_lambda_powertools.logging import correlation_paths -from aws_lambda_powertools.utilities.typing import LambdaContext from aws_lambda_powertools.event_handler.api_gateway import ApiGatewayResolver +from aws_lambda_powertools.logging import correlation_paths +from aws_lambda_powertools.metrics import MetricUnit -# https://awslabs.github.io/aws-lambda-powertools-python/#features -tracer = Tracer() -logger = Logger() -metrics = Metrics() +logger = Logger(service="APP") +tracer = Tracer(service="APP") +metrics = Metrics(namespace="MyApp", service="APP") app = ApiGatewayResolver() -# Global variables are reused across execution contexts (if available) -# session = boto3.Session() + +@app.get("/hello/") +@tracer.capture_method +def hello_name(name): + tracer.put_annotation(key="User", value=name) + logger.info(f"Request from {name} received") + metrics.add_metric(name="SuccessfulGreetings", unit=MetricUnit.Count, value=1) + return {"message": f"hello {name}!"} + @app.get("/hello") +@tracer.capture_method def hello(): - query_string_name = app.current_event.get_query_string_value(name="name", default_value="universe") - return {"message": f"hello {query_string_name}"} - + tracer.put_annotation(key="User", value="unknown") + logger.info("Request from unknown received") + metrics.add_metric(name="SuccessfulGreetings", unit=MetricUnit.Count, value=1) + return {"message": "hello unknown!"} -@app.get("/hello/") -def hello_you(name): - # query_strings_as_dict = app.current_event.query_string_parameters - # json_payload = app.current_event.json_body - return {"message": f"hello {name}"} -@metrics.log_metrics(capture_cold_start_metric=True) -@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST) @tracer.capture_lambda_handler -def lambda_handler(event, context: LambdaContext): +@logger.inject_lambda_context( + correlation_id_path=correlation_paths.API_GATEWAY_REST, log_event=True +) +@metrics.log_metrics(capture_cold_start_metric=True) +def lambda_handler(event, context): try: return app.resolve(event, context) except Exception as e: diff --git a/{{ cookiecutter.project_name }}/tests/conftest.py b/{{ cookiecutter.project_name }}/tests/conftest.py index 72e66b9..3b3ee5c 100644 --- a/{{ cookiecutter.project_name }}/tests/conftest.py +++ b/{{ cookiecutter.project_name }}/tests/conftest.py @@ -5,12 +5,13 @@ class MockContext(object): - def __init__(self, function_name): self.function_name = function_name self.function_version = "v$LATEST" self.memory_limit_in_mb = 512 - self.invoked_function_arn = f"arn:aws:lambda:us-east-1:ACCOUNT:function:{self.function_name}" + self.invoked_function_arn = ( + f"arn:aws:lambda:us-east-1:ACCOUNT:function:{self.function_name}" + ) self.aws_request_id = str(uuid4) @@ -20,7 +21,14 @@ def lambda_context(): @pytest.fixture() -def apigw_event(): - """ Generates API GW Event""" - with open("./events/hello_world_event.json", "r") as fp: +def apigw_hello_event(): + """Generates API GW Event""" + with open("./events/hello.json", "r") as fp: + return json.load(fp) + + +@pytest.fixture() +def apigw_hello_name_event(): + """Generates API GW Event""" + with open("./events/hello_name.json", "r") as fp: return json.load(fp) diff --git a/{{ cookiecutter.project_name }}/tests/unit/test_hello_function.py b/{{ cookiecutter.project_name }}/tests/unit/test_hello_function.py new file mode 100644 index 0000000..74c75f4 --- /dev/null +++ b/{{ cookiecutter.project_name }}/tests/unit/test_hello_function.py @@ -0,0 +1,19 @@ +import json + +from hello_world import app + + +def test_lambda_handler_hello_path(apigw_hello_event, lambda_context): + ret = app.lambda_handler(apigw_hello_event, lambda_context) + expected = json.dumps({"message": "hello unknown!"}, separators=(",", ":")) + + assert ret["statusCode"] == 200 + assert ret["body"] == expected + + +def test_lambda_handler_hello_you_path(apigw_hello_name_event, lambda_context): + ret = app.lambda_handler(apigw_hello_name_event, lambda_context) + expected = json.dumps({"message": "hello you!"}, separators=(",", ":")) + + assert ret["statusCode"] == 200 + assert ret["body"] == expected diff --git a/{{ cookiecutter.project_name }}/tests/unit/test_hello_world_function.py b/{{ cookiecutter.project_name }}/tests/unit/test_hello_world_function.py deleted file mode 100644 index c19487a..0000000 --- a/{{ cookiecutter.project_name }}/tests/unit/test_hello_world_function.py +++ /dev/null @@ -1,11 +0,0 @@ -import json - -from hello_world import app - - -def test_lambda_handler(apigw_event, lambda_context): - ret = app.lambda_handler(apigw_event, lambda_context) - expected = json.dumps({"message": "hello universe"}, separators=(",", ":")) - - assert ret["statusCode"] == 200 - assert ret["body"] == expected