Skip to content

docs(event-handler): snippets split, improved, and lint #1279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,166 changes: 148 additions & 1,018 deletions docs/core/event_handler/api_gateway.md

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions docs/core/logger.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ Logger provides an opinionated logger with output structured as JSON.

## Getting started

???+ tip
All examples shared in this documentation are available within the [project repository](https://github.com/awslabs/aws-lambda-powertools-python/tree/develop/examples){target="_blank"}.

Logger requires two settings:

| Setting | Description | Environment variable | Constructor parameter |
Expand Down
3 changes: 3 additions & 0 deletions docs/core/metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ If you're new to Amazon CloudWatch, there are two terminologies you must be awar

## Getting started

???+ tip
All examples shared in this documentation are available within the [project repository](https://github.com/awslabs/aws-lambda-powertools-python/tree/develop/examples){target="_blank"}.

Metric has two global settings that will be used across all metrics emitted:

| Setting | Description | Environment variable | Constructor parameter |
Expand Down
3 changes: 3 additions & 0 deletions docs/core/tracer.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ Tracer is an opinionated thin wrapper for [AWS X-Ray Python SDK](https://github.

## Getting started

???+ tip
All examples shared in this documentation are available within the [project repository](https://github.com/awslabs/aws-lambda-powertools-python/tree/develop/examples){target="_blank"}.

### Permissions

Before your use this utility, your AWS Lambda function [must have permissions](https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html#services-xray-permissions) to send traces to AWS X-Ray.
Expand Down
56 changes: 56 additions & 0 deletions examples/event_handler_rest/sam/template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: Hello world event handler API Gateway

Globals:
Api:
TracingEnabled: true
Cors: # see CORS section
AllowOrigin: "'https://example.com'"
AllowHeaders: "'Content-Type,Authorization,X-Amz-Date'"
MaxAge: "'300'"
BinaryMediaTypes: # see Binary responses section
- "*~1*" # converts to */* for any binary type
Function:
Timeout: 5
Runtime: python3.8
Tracing: Active
Environment:
Variables:
LOG_LEVEL: INFO
POWERTOOLS_LOGGER_SAMPLE_RATE: 0.1
POWERTOOLS_LOGGER_LOG_EVENT: true
POWERTOOLS_SERVICE_NAME: example

Resources:
ApiFunction:
Type: AWS::Serverless::Function
Properties:
Handler: app.lambda_handler
CodeUri: api_handler/
Description: API handler function
Events:
AnyApiEvent:
Type: Api
Properties:
# NOTE: this is a catch-all rule to simplify the documentation.
# explicit routes and methods are recommended for prod instead (see below)
Path: /{proxy+} # Send requests on any path to the lambda function
Method: ANY # Send requests using any http method to the lambda function


# GetAllTodos:
# Type: Api
# Properties:
# Path: /todos
# Method: GET
# GetTodoById:
# Type: Api
# Properties:
# Path: /todos/{todo_id}
# Method: GET
# CreateTodo:
# Type: Api
# Properties:
# Path: /todos
# Method: POST
40 changes: 40 additions & 0 deletions examples/event_handler_rest/src/accessing_request_details.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from typing import Optional

import requests
from requests import Response

from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()
app = APIGatewayRestResolver()


@app.get("/todos")
@tracer.capture_method
def get_todos():
todo_id: str = app.current_event.get_query_string_value(name="id", default_value="")
# alternatively
_: Optional[str] = app.current_event.query_string_parameters.get("id")

# Payload
_: Optional[str] = app.current_event.body # raw str | None

endpoint = "https://jsonplaceholder.typicode.com/todos"
if todo_id:
endpoint = f"{endpoint}/{todo_id}"

todos: Response = requests.get(endpoint)
todos.raise_for_status()

return {"todos": todos.json()}


# You can continue to use other utilities just as before
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import requests
from requests import Response

from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()
app = APIGatewayRestResolver()


@app.get("/todos")
@tracer.capture_method
def get_todos():
endpoint = "https://jsonplaceholder.typicode.com/todos"

api_key: str = app.current_event.get_header_value(name="X-Api-Key", case_sensitive=True, default_value="")
todos: Response = requests.get(endpoint, headers={"X-Api-Key": api_key})
todos.raise_for_status()

return {"todos": todos.json()}


# You can continue to use other utilities just as before
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
28 changes: 28 additions & 0 deletions examples/event_handler_rest/src/assert_http_response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from dataclasses import dataclass

import assert_http_response_module
import pytest


@pytest.fixture
def lambda_context():
@dataclass
class LambdaContext:
function_name: str = "test"
memory_limit_in_mb: int = 128
invoked_function_arn: str = "arn:aws:lambda:eu-west-1:123456789012:function:test"
aws_request_id: str = "da658bd3-2d6f-4e7b-8ec2-937234644fdc"

return LambdaContext()


def test_lambda_handler(lambda_context):
minimal_event = {
"path": "/todos",
"httpMethod": "GET",
"requestContext": {"requestId": "227b78aa-779d-47d4-a48e-ce62120393b8"}, # correlation ID
}

ret = assert_http_response_module.lambda_handler(minimal_event, lambda_context)
assert ret["statusCode"] == 200
assert ret["body"] != ""
27 changes: 27 additions & 0 deletions examples/event_handler_rest/src/assert_http_response_module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import requests
from requests import Response

from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()
app = APIGatewayRestResolver()


@app.get("/todos")
@tracer.capture_method
def get_todos():
todos: Response = requests.get("https://jsonplaceholder.typicode.com/todos")
todos.raise_for_status()

return {"todos": todos.json()[:10]}


# You can continue to use other utilities just as before
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
8 changes: 8 additions & 0 deletions examples/event_handler_rest/src/binary_responses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"headers": {
"Accept": "image/svg+xml"
},
"resource": "/logo",
"path": "/logo",
"httpMethod": "GET"
}
27 changes: 27 additions & 0 deletions examples/event_handler_rest/src/binary_responses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import os
from pathlib import Path

from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler.api_gateway import APIGatewayRestResolver, Response
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()


app = APIGatewayRestResolver()
logo_file: bytes = Path(os.getenv("LAMBDA_TASK_ROOT") + "/logo.svg").read_bytes()


@app.get("/logo")
@tracer.capture_method
def get_logo():
return Response(status_code=200, content_type="image/svg+xml", body=logo_file)


# You can continue to use other utilities just as before
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
14 changes: 14 additions & 0 deletions examples/event_handler_rest/src/binary_responses_logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"body": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMjU2cHgiIGhlaWdodD0iMjU2cHgiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHByZXNlcnZlQXNwZWN0UmF0aW89InhNaWRZTWlkIj4KICAgIDx0aXRsZT5BV1MgTGFtYmRhPC90aXRsZT4KICAgIDxkZWZzPgogICAgICAgIDxsaW5lYXJHcmFkaWVudCB4MT0iMCUiIHkxPSIxMDAlIiB4Mj0iMTAwJSIgeTI9IjAlIiBpZD0ibGluZWFyR3JhZGllbnQtMSI+CiAgICAgICAgICAgIDxzdG9wIHN0b3AtY29sb3I9IiNDODUxMUIiIG9mZnNldD0iMCUiPjwvc3RvcD4KICAgICAgICAgICAgPHN0b3Agc3RvcC1jb2xvcj0iI0ZGOTkwMCIgb2Zmc2V0PSIxMDAlIj48L3N0b3A+CiAgICAgICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDwvZGVmcz4KICAgIDxnPgogICAgICAgIDxyZWN0IGZpbGw9InVybCgjbGluZWFyR3JhZGllbnQtMSkiIHg9IjAiIHk9IjAiIHdpZHRoPSIyNTYiIGhlaWdodD0iMjU2Ij48L3JlY3Q+CiAgICAgICAgPHBhdGggZD0iTTg5LjYyNDExMjYsMjExLjIgTDQ5Ljg5MDMyNzcsMjExLjIgTDkzLjgzNTQ4MzIsMTE5LjM0NzIgTDExMy43NDcyOCwxNjAuMzM5MiBMODkuNjI0MTEyNiwyMTEuMiBaIE05Ni43MDI5MzU3LDExMC41Njk2IEM5Ni4xNjQwODU4LDEwOS40NjU2IDk1LjA0MTQ4MTMsMTA4Ljc2NDggOTMuODE2MjM4NCwxMDguNzY0OCBMOTMuODA2NjE2MywxMDguNzY0OCBDOTIuNTcxNzUxNCwxMDguNzY4IDkxLjQ0OTE0NjYsMTA5LjQ3NTIgOTAuOTE5OTE4NywxMTAuNTg1NiBMNDEuOTEzNDIwOCwyMTMuMDIwOCBDNDEuNDM4NzE5NywyMTQuMDEyOCA0MS41MDYwNzU4LDIxNS4xNzc2IDQyLjA5NjI0NTEsMjE2LjEwODggQzQyLjY3OTk5OTQsMjE3LjAzNjggNDMuNzA2MzgwNSwyMTcuNiA0NC44MDY1MzMxLDIxNy42IEw5MS42NTQ0MjMsMjE3LjYgQzkyLjg5NTcwMjcsMjE3LjYgOTQuMDIxNTE0OSwyMTYuODg2NCA5NC41NTM5NTAxLDIxNS43Njk2IEwxMjAuMjAzODU5LDE2MS42ODk2IEMxMjAuNjE3NjE5LDE2MC44MTI4IDEyMC42MTQ0MTIsMTU5Ljc5ODQgMTIwLjE4NzgyMiwxNTguOTI4IEw5Ni43MDI5MzU3LDExMC41Njk2IFogTTIwNy45ODUxMTcsMjExLjIgTDE2OC41MDc5MjgsMjExLjIgTDEwNS4xNzM3ODksNzguNjI0IEMxMDQuNjQ0NTYxLDc3LjUxMDQgMTAzLjUxNTU0MSw3Ni44IDEwMi4yNzc0NjksNzYuOCBMNzYuNDQ3OTQzLDc2LjggTDc2LjQ3NjgwOTksNDQuOCBMMTI3LjEwMzA2Niw0NC44IEwxOTAuMTQ1MzI4LDE3Ny4zNzI4IEMxOTAuNjc0NTU2LDE3OC40ODY0IDE5MS44MDM1NzUsMTc5LjIgMTkzLjA0MTY0NywxNzkuMiBMMjA3Ljk4NTExNywxNzkuMiBMMjA3Ljk4NTExNywyMTEuMiBaIE0yMTEuMTkyNTU4LDE3Mi44IEwxOTUuMDcxOTU4LDE3Mi44IEwxMzIuMDI5Njk2LDQwLjIyNzIgQzEzMS41MDA0NjgsMzkuMTEzNiAxMzAuMzcxNDQ5LDM4LjQgMTI5LjEzMDE2OSwzOC40IEw3My4yNzI1NzYsMzguNCBDNzEuNTA1Mjc1OCwzOC40IDcwLjA2ODM0MjEsMzkuODMwNCA3MC4wNjUxMzQ0LDQxLjU5NjggTDcwLjAyOTg1MjgsNzkuOTk2OCBDNzAuMDI5ODUyOCw4MC44NDggNzAuMzYzNDI2Niw4MS42NjA4IDcwLjk2OTYzMyw4Mi4yNjI0IEM3MS41Njk0MjQ2LDgyLjg2NCA3Mi4zODQxMTQ2LDgzLjIgNzMuMjM3Mjk0MSw4My4yIEwxMDAuMjUzNTczLDgzLjIgTDE2My41OTA5MiwyMTUuNzc2IEMxNjQuMTIzMzU1LDIxNi44ODk2IDE2NS4yNDU5NiwyMTcuNiAxNjYuNDg0MDMyLDIxNy42IEwyMTEuMTkyNTU4LDIxNy42IEMyMTIuOTY2Mjc0LDIxNy42IDIxNC40LDIxNi4xNjY0IDIxNC40LDIxNC40IEwyMTQuNCwxNzYgQzIxNC40LDE3NC4yMzM2IDIxMi45NjYyNzQsMTcyLjggMjExLjE5MjU1OCwxNzIuOCBMMjExLjE5MjU1OCwxNzIuOCBaIiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+CiAgICA8L2c+Cjwvc3ZnPg==",
"headers": {
"Content-Type": "image/svg+xml"
},
"isBase64Encoded": true,
"statusCode": 200
}
8 changes: 8 additions & 0 deletions examples/event_handler_rest/src/compressing_responses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"headers": {
"Accept-Encoding": "gzip"
},
"resource": "/todos",
"path": "/todos",
"httpMethod": "GET"
}
28 changes: 28 additions & 0 deletions examples/event_handler_rest/src/compressing_responses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import requests
from requests import Response

from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()
app = APIGatewayRestResolver()


@app.get("/todos", compress=True)
@tracer.capture_method
def get_todos():
todos: Response = requests.get("https://jsonplaceholder.typicode.com/todos")
todos.raise_for_status()

# for brevity, we'll limit to the first 10 only
return {"todos": todos.json()[:10]}


# You can continue to use other utilities just as before
@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"statusCode": 200,
"headers": {
"Content-Type": "application/json",
"Content-Encoding": "gzip"
},
"body": "H4sIAAAAAAACE42STU4DMQyFrxJl3QXln96AMyAW7sSDLCVxiJ0Kqerd8TCCUOgii1EmP/783pOPXjmw+N3L0TfB+hz8brvxtC5KGtHvfMCIkzZx0HT5MPmNnziViIr2dIYoeNr8Q1x3xHsjcVadIbkZJoq2RXU8zzQROLseQ9505NzeCNQdMJNBE+UmY4zbzjAJhWtlZ57sB84BWtul+rteH2HPlVgWARwjqXkxpklK5gmEHAQqJBMtFsGVygcKmNVRjG0wxvuzGF2L0dpVUOKMC3bfJNjJgWMrCuZk7cUp02AiD72D6WKHHwUDKbiJs6AZ0VZXKOUx4uNvzdxT+E4mLcMA+6G8nzrLQkaxkNEVrFKW2VGbJCoCY7q2V3+tiv5kGThyxfTecDWbgGz/NfYXhL6ePgF9PnFdPgMAAA==",
"isBase64Encoded": true
}
5 changes: 5 additions & 0 deletions examples/event_handler_rest/src/custom_api_mapping.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"resource": "/subscriptions/{subscription}",
"path": "/payment/subscriptions/123",
"httpMethod": "GET"
}
20 changes: 20 additions & 0 deletions examples/event_handler_rest/src/custom_api_mapping.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from aws_lambda_powertools import Logger, Tracer
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
from aws_lambda_powertools.logging import correlation_paths
from aws_lambda_powertools.utilities.typing import LambdaContext

tracer = Tracer()
logger = Logger()
app = APIGatewayRestResolver(strip_prefixes=["/payment"])


@app.get("/subscriptions/<subscription>")
@tracer.capture_method
def get_subscription(subscription):
return {"subscription_id": subscription}


@logger.inject_lambda_context(correlation_id_path=correlation_paths.API_GATEWAY_REST)
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> dict:
return app.resolve(event, context)
Loading