Repository: localstack/localstack

Issue:
path being passed into event missing trailing slash 
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Current Behavior

event path doesn't have trailing slash

### Expected Behavior

event path should have trailing slash

### How are you starting LocalStack?

With a docker-compose file

### Steps To Reproduce

{**'path': '/get_presigned_url'**, 'headers': {'Host': '0vcomlwzdi.execute-api.localhost.localstack.cloud:4566', .... more event logs .... }

### Environment

```markdown
- OS: Mac m1 
- LocalStack: 1.0.1
```


### Anything else?

noticing this while running a lambda test against localstack...in AWS the trailing slash in present


Discussion:
Hey Peter @kingster307, thanks for reporting. Could you be a bit more specific about what events you mean? Are those s3 notifications configurations triggering a lambda? If so, could you please post the s3 notification configuration?
@thrau event object coming into lambda when lambda is invoked from a rest apigw 
Hi @kingster307 !
I just tried a setup using ApiGateway with a proxy integration. The resulting event in lambda is something like this:
```
{
    "resource": "/sample-resource",
    "path": "/sample-resource",
    "httpMethod": "GET",
```
I can see no trailing slash here. Could you perhaps give an example of a setup which leads to the behavior you are describing?
Nevermind, I think I see the problem, it seems like a trailing slash is not correctly set into the path, if the request url does contain such a trailing slash. I will investigate more and get back to you.

Resolving patch:
diff --git a/localstack/services/apigateway/helpers.py b/localstack/services/apigateway/helpers.py
--- a/localstack/services/apigateway/helpers.py
+++ b/localstack/services/apigateway/helpers.py
@@ -401,8 +401,7 @@ def extract_query_string_params(path: str) -> Tuple[str, Dict[str, str]]:
         else:
             query_string_params[query_param_name] = query_param_values
 
-    # strip trailing slashes from path to fix downstream lookups
-    path = path.rstrip("/") or "/"
+    path = path or "/"
     return path, query_string_params
 
 
@@ -763,7 +762,7 @@ def get_target_resource_details(invocation_context: ApiInvocationContext) -> Tup
     path_map = get_rest_api_paths(
         rest_api_id=invocation_context.api_id, region_name=invocation_context.region_name
     )
-    relative_path = invocation_context.invocation_path
+    relative_path = invocation_context.invocation_path.rstrip("/") or "/"
     try:
         extracted_path, resource = get_resource_for_path(path=relative_path, path_map=path_map)
         invocation_context.resource = resource
diff --git a/localstack/services/apigateway/provider.py b/localstack/services/apigateway/provider.py
--- a/localstack/services/apigateway/provider.py
+++ b/localstack/services/apigateway/provider.py
@@ -118,7 +118,14 @@ def on_after_init(self):
 
     @handler("CreateRestApi", expand=False)
     def create_rest_api(self, context: RequestContext, request: CreateRestApiRequest) -> RestApi:
-        return call_moto(context)
+        result = call_moto(context)
+        if not result.get("binaryMediaTypes"):
+            result.pop("binaryMediaTypes")
+        if not result.get("tags"):
+            result.pop("tags")
+        if result.get("version") == "V1":
+            result.pop("version")
+        return result
 
     def delete_rest_api(self, context: RequestContext, rest_api_id: String) -> None:
         try:


Test patch:
diff --git a/localstack/testing/snapshots/transformer_utility.py b/localstack/testing/snapshots/transformer_utility.py
--- a/localstack/testing/snapshots/transformer_utility.py
+++ b/localstack/testing/snapshots/transformer_utility.py
@@ -9,6 +9,7 @@
     RegexTransformer,
     ResponseMetaDataTransformer,
 )
+from localstack.utils.net import IP_REGEX
 
 PATTERN_UUID = re.compile(
     r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"
@@ -110,6 +111,41 @@ def lambda_api():
             ),
         ]
 
+    @staticmethod
+    def apigateway_api():
+        return [
+            TransformerUtility.key_value("id"),
+            TransformerUtility.key_value("name"),
+        ]
+
+    @staticmethod
+    def apigateway_proxy_event():
+        return [
+            TransformerUtility.key_value("extendedRequestId"),
+            TransformerUtility.key_value("resourceId"),
+            TransformerUtility.key_value("sourceIp"),
+            TransformerUtility.jsonpath("$..headers.X-Amz-Cf-Id", value_replacement="cf-id"),
+            TransformerUtility.jsonpath(
+                "$..headers.CloudFront-Viewer-ASN", value_replacement="cloudfront-asn"
+            ),
+            TransformerUtility.jsonpath(
+                "$..headers.CloudFront-Viewer-Country", value_replacement="cloudfront-country"
+            ),
+            TransformerUtility.jsonpath("$..headers.Via", value_replacement="via"),
+            TransformerUtility.jsonpath("$..headers.X-Amzn-Trace-Id", value_replacement="trace-id"),
+            TransformerUtility.jsonpath(
+                "$..requestContext.requestTime",
+                value_replacement="<request-time>",
+                reference_replacement=False,
+            ),
+            KeyValueBasedTransformer(
+                lambda k, v: str(v) if k == "requestTimeEpoch" else None,
+                "<request-time-epoch>",
+                replace_reference=False,
+            ),
+            TransformerUtility.regex(IP_REGEX.strip("^$"), "<ip>"),
+        ]
+
     @staticmethod
     def cloudformation_api():
         """
diff --git a/tests/integration/awslambda/functions/lambda_aws_proxy.py b/tests/integration/awslambda/functions/lambda_aws_proxy.py
--- a/tests/integration/awslambda/functions/lambda_aws_proxy.py
+++ b/tests/integration/awslambda/functions/lambda_aws_proxy.py
@@ -7,4 +7,5 @@ def handler(event, context):
     return {
         "statusCode": 200,
         "body": json.dumps(event),
+        "isBase64Encoded": False,
     }
diff --git a/tests/integration/test_apigateway_integrations.py b/tests/integration/test_apigateway_integrations.py
--- a/tests/integration/test_apigateway_integrations.py
+++ b/tests/integration/test_apigateway_integrations.py
@@ -1,3 +1,5 @@
+import json
+
 import pytest
 import requests
 
@@ -5,6 +7,7 @@
 from localstack.services.awslambda.lambda_utils import LAMBDA_RUNTIME_PYTHON39
 from localstack.utils.aws import aws_stack
 from localstack.utils.strings import short_uid
+from localstack.utils.sync import retry
 from localstack.utils.testutil import create_lambda_function
 from tests.integration.apigateway_fixtures import (
     api_invoke_url,
@@ -12,7 +15,7 @@
     create_rest_resource,
     create_rest_resource_method,
 )
-from tests.integration.awslambda.test_lambda import TEST_LAMBDA_HELLO_WORLD
+from tests.integration.awslambda.test_lambda import TEST_LAMBDA_AWS_PROXY, TEST_LAMBDA_HELLO_WORLD
 
 
 @pytest.mark.skip_offline
@@ -83,6 +86,190 @@ def test_lambda_aws_integration(apigateway_client, create_rest_apigw):
     assert response.json() == {"message": "Hello from Lambda"}
 
 
+@pytest.mark.aws_validated
+@pytest.mark.skip_snapshot_verify(
+    paths=[
+        "$..body",
+        "$..headers.Accept",
+        "$..headers.Accept-Encoding",
+        "$..headers.Authorization",
+        "$..headers.CloudFront-Forwarded-Proto",
+        "$..headers.CloudFront-Is-Desktop-Viewer",
+        "$..headers.CloudFront-Is-Mobile-Viewer",
+        "$..headers.CloudFront-Is-SmartTV-Viewer",
+        "$..headers.CloudFront-Is-Tablet-Viewer",
+        "$..headers.CloudFront-Viewer-ASN",
+        "$..headers.CloudFront-Viewer-Country",
+        "$..headers.Connection",
+        "$..headers.Host",
+        "$..headers.Remote-Addr",
+        "$..headers.Via",
+        "$..headers.X-Amz-Cf-Id",
+        "$..headers.X-Amzn-Trace-Id",
+        "$..headers.X-Forwarded-For",
+        "$..headers.X-Forwarded-Port",
+        "$..headers.X-Forwarded-Proto",
+        "$..headers.accept",
+        "$..headers.accept-encoding",
+        "$..headers.x-localstack-edge",
+        "$..headers.x-localstack-request-url",
+        "$..headers.x-localstack-tgt-api",
+        "$..multiValueHeaders.Accept",
+        "$..multiValueHeaders.Accept-Encoding",
+        "$..multiValueHeaders.Authorization",
+        "$..multiValueHeaders.CloudFront-Forwarded-Proto",
+        "$..multiValueHeaders.CloudFront-Is-Desktop-Viewer",
+        "$..multiValueHeaders.CloudFront-Is-Mobile-Viewer",
+        "$..multiValueHeaders.CloudFront-Is-SmartTV-Viewer",
+        "$..multiValueHeaders.CloudFront-Is-Tablet-Viewer",
+        "$..multiValueHeaders.CloudFront-Viewer-ASN",
+        "$..multiValueHeaders.CloudFront-Viewer-Country",
+        "$..multiValueHeaders.Connection",
+        "$..multiValueHeaders.Host",
+        "$..multiValueHeaders.Remote-Addr",
+        "$..multiValueHeaders.Via",
+        "$..multiValueHeaders.X-Amz-Cf-Id",
+        "$..multiValueHeaders.X-Amzn-Trace-Id",
+        "$..multiValueHeaders.X-Forwarded-For",
+        "$..multiValueHeaders.X-Forwarded-Port",
+        "$..multiValueHeaders.X-Forwarded-Proto",
+        "$..multiValueHeaders.accept",
+        "$..multiValueHeaders.accept-encoding",
+        "$..multiValueHeaders.x-localstack-edge",
+        "$..multiValueHeaders.x-localstack-request-url",
+        "$..multiValueHeaders.x-localstack-tgt-api",
+        "$..pathParameters",
+        "$..requestContext.authorizer",
+        "$..requestContext.domainName",
+        "$..requestContext.extendedRequestId",
+        "$..requestContext.identity.accessKey",
+        "$..requestContext.identity.accountId",
+        "$..requestContext.identity.caller",
+        "$..requestContext.identity.cognitoAuthenticationProvider",
+        "$..requestContext.identity.cognitoAuthenticationType",
+        "$..requestContext.identity.cognitoIdentityId",
+        "$..requestContext.identity.cognitoIdentityPoolId",
+        "$..requestContext.identity.principalOrgId",
+        "$..requestContext.identity.user",
+        "$..requestContext.identity.userArn",
+        "$..stageVariables",
+    ]
+)
+def test_lambda_proxy_integration(
+    apigateway_client,
+    create_lambda_function,
+    lambda_client,
+    create_role,
+    create_policy,
+    iam_client,
+    snapshot,
+    cleanups,
+):
+    function_name = f"test-function-{short_uid()}"
+    role_name = f"test-role-{short_uid()}"
+    stage_name = "test"
+    snapshot.add_transformer(snapshot.transform.apigateway_api())
+    snapshot.add_transformer(snapshot.transform.apigateway_proxy_event())
+
+    # create lambda
+    create_function_response = create_lambda_function(
+        func_name=function_name,
+        handler_file=TEST_LAMBDA_AWS_PROXY,
+        handler="lambda_aws_proxy.handler",
+        runtime=LAMBDA_RUNTIME_PYTHON39,
+    )
+    # create invocation role
+    assume_role_doc = {
+        "Version": "2012-10-17",
+        "Statement": [
+            {
+                "Action": "sts:AssumeRole",
+                "Principal": {"Service": "apigateway.amazonaws.com"},
+                "Effect": "Allow",
+            }
+        ],
+    }
+    policy_doc = {
+        "Version": "2012-10-17",
+        "Statement": [{"Effect": "Allow", "Action": "lambda:InvokeFunction", "Resource": "*"}],
+    }
+    role_arn = create_role(
+        RoleName=role_name, AssumeRolePolicyDocument=json.dumps(assume_role_doc)
+    )["Role"]["Arn"]
+    policy_arn = create_policy(
+        PolicyName=f"test-policy-{short_uid()}", PolicyDocument=json.dumps(policy_doc)
+    )["Policy"]["Arn"]
+    iam_client.attach_role_policy(RoleName=role_name, PolicyArn=policy_arn)
+    lambda_arn = create_function_response["CreateFunctionResponse"]["FunctionArn"]
+
+    # create rest api
+    rest_api_creation_response = apigateway_client.create_rest_api(
+        name=f"test-api-{short_uid()}", description="Integration test API"
+    )
+    snapshot.match("rest-api-creation", rest_api_creation_response)
+    cleanups.append(lambda: apigateway_client.delete_rest_api(restApiId=rest_api_id))
+    rest_api_id = rest_api_creation_response["id"]
+    root_resource_id = apigateway_client.get_resources(restApiId=rest_api_id)["items"][0]["id"]
+    resource_id = apigateway_client.create_resource(
+        restApiId=rest_api_id, parentId=root_resource_id, pathPart="test-path"
+    )["id"]
+    apigateway_client.put_method(
+        restApiId=rest_api_id,
+        resourceId=resource_id,
+        httpMethod="ANY",
+        authorizationType="NONE",
+    )
+    apigateway_client.put_integration(
+        restApiId=rest_api_id,
+        resourceId=resource_id,
+        httpMethod="ANY",
+        type="AWS_PROXY",
+        integrationHttpMethod="POST",
+        uri=f"arn:aws:apigateway:{apigateway_client.meta.region_name}:lambda:path/2015-03-31/functions/{lambda_arn}/invocations",
+        credentials=role_arn,
+    )
+    apigateway_client.create_deployment(restApiId=rest_api_id, stageName=stage_name)
+
+    # invoke rest api
+    invocation_url = api_invoke_url(
+        api_id=rest_api_id,
+        stage=stage_name,
+        path="/test-path",
+    )
+
+    def invoke_api(url):
+        # use test header with different casing to check if it is preserved in the proxy payload
+        response = requests.get(
+            url,
+            headers={"User-Agent": "python-requests/testing", "tEsT-HEADeR": "aValUE"},
+            verify=False,
+        )
+        assert 200 == response.status_code
+        return response
+
+    # retry is necessary against AWS, probably IAM permission delay
+    response = retry(invoke_api, sleep=2, retries=10, url=invocation_url)
+    snapshot.match("invocation-payload-without-trailing-slash", response.json())
+
+    # invoke rest api with trailing slash
+    response_trailing_slash = retry(invoke_api, sleep=2, retries=10, url=f"{invocation_url}/")
+    snapshot.match("invocation-payload-with-trailing-slash", response_trailing_slash.json())
+    response_trailing_slash = retry(
+        invoke_api, sleep=2, retries=10, url=f"{invocation_url}?urlparam=test"
+    )
+    snapshot.match(
+        "invocation-payload-without-trailing-slash-and-query-params",
+        response_trailing_slash.json(),
+    )
+    response_trailing_slash = retry(
+        invoke_api, sleep=2, retries=10, url=f"{invocation_url}/?urlparam=test"
+    )
+    snapshot.match(
+        "invocation-payload-with-trailing-slash-and-query-params",
+        response_trailing_slash.json(),
+    )
+
+
 #
 # def test_aws_integration_dynamodb(apigateway_client):
 #     if settings.TEST_SERVER_MODE:
diff --git a/tests/integration/test_apigateway_integrations.snapshot.json b/tests/integration/test_apigateway_integrations.snapshot.json
new file mode 100644
--- /dev/null
+++ b/tests/integration/test_apigateway_integrations.snapshot.json
@@ -0,0 +1,504 @@
+{
+  "tests/integration/test_apigateway_integrations.py::test_lambda_proxy_integration": {
+    "recorded-date": "30-08-2022, 14:23:53",
+    "recorded-content": {
+      "rest-api-creation": {
+        "ResponseMetadata": {
+          "HTTPHeaders": {},
+          "HTTPStatusCode": 201
+        },
+        "apiKeySource": "HEADER",
+        "createdDate": "datetime",
+        "description": "Integration test API",
+        "disableExecuteApiEndpoint": false,
+        "endpointConfiguration": {
+          "types": [
+            "EDGE"
+          ]
+        },
+        "id": "<id:1>",
+        "name": "<name:1>"
+      },
+      "invocation-payload-without-trailing-slash": {
+        "body": null,
+        "headers": {
+          "Accept": "*/*",
+          "Accept-Encoding": "gzip, deflate",
+          "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-ASN": "<cloudfront-asn:1>",
+          "CloudFront-Viewer-Country": "<cloudfront-country:1>",
+          "Host": "<id:1>.execute-api.<region>.amazonaws.com",
+          "User-Agent": "python-requests/testing",
+          "Via": "<via:1>",
+          "X-Amz-Cf-Id": "<cf-id:1>",
+          "X-Amzn-Trace-Id": "<trace-id:1>",
+          "X-Forwarded-For": "<source-ip:1>, <ip>",
+          "X-Forwarded-Port": "443",
+          "X-Forwarded-Proto": "https",
+          "tEsT-HEADeR": "aValUE"
+        },
+        "httpMethod": "GET",
+        "isBase64Encoded": false,
+        "multiValueHeaders": {
+          "Accept": [
+            "*/*"
+          ],
+          "Accept-Encoding": [
+            "gzip, deflate"
+          ],
+          "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-ASN": [
+            "<cloudfront-asn:1>"
+          ],
+          "CloudFront-Viewer-Country": [
+            "<cloudfront-country:1>"
+          ],
+          "Host": [
+            "<id:1>.execute-api.<region>.amazonaws.com"
+          ],
+          "User-Agent": [
+            "python-requests/testing"
+          ],
+          "Via": [
+            "<via:1>"
+          ],
+          "X-Amz-Cf-Id": [
+            "<cf-id:1>"
+          ],
+          "X-Amzn-Trace-Id": [
+            "<trace-id:1>"
+          ],
+          "X-Forwarded-For": [
+            "<source-ip:1>, <ip>"
+          ],
+          "X-Forwarded-Port": [
+            "443"
+          ],
+          "X-Forwarded-Proto": [
+            "https"
+          ],
+          "tEsT-HEADeR": [
+            "aValUE"
+          ]
+        },
+        "multiValueQueryStringParameters": null,
+        "path": "/test-path",
+        "pathParameters": null,
+        "queryStringParameters": null,
+        "requestContext": {
+          "accountId": "111111111111",
+          "apiId": "<id:1>",
+          "domainName": "<id:1>.execute-api.<region>.amazonaws.com",
+          "domainPrefix": "<id:1>",
+          "extendedRequestId": "<extended-request-id:1>",
+          "httpMethod": "GET",
+          "identity": {
+            "accessKey": null,
+            "accountId": null,
+            "caller": null,
+            "cognitoAuthenticationProvider": null,
+            "cognitoAuthenticationType": null,
+            "cognitoIdentityId": null,
+            "cognitoIdentityPoolId": null,
+            "principalOrgId": null,
+            "sourceIp": "<source-ip:1>",
+            "user": null,
+            "userAgent": "python-requests/testing",
+            "userArn": null
+          },
+          "path": "/test/test-path",
+          "protocol": "HTTP/1.1",
+          "requestId": "<uuid:1>",
+          "requestTime": "<request-time>",
+          "requestTimeEpoch": "<request-time-epoch>",
+          "resourceId": "<resource-id:1>",
+          "resourcePath": "/test-path",
+          "stage": "test"
+        },
+        "resource": "/test-path",
+        "stageVariables": null
+      },
+      "invocation-payload-with-trailing-slash": {
+        "body": null,
+        "headers": {
+          "Accept": "*/*",
+          "Accept-Encoding": "gzip, deflate",
+          "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-ASN": "<cloudfront-asn:1>",
+          "CloudFront-Viewer-Country": "<cloudfront-country:1>",
+          "Host": "<id:1>.execute-api.<region>.amazonaws.com",
+          "User-Agent": "python-requests/testing",
+          "Via": "<via:2>",
+          "X-Amz-Cf-Id": "<cf-id:2>",
+          "X-Amzn-Trace-Id": "<trace-id:2>",
+          "X-Forwarded-For": "<source-ip:1>, <ip>",
+          "X-Forwarded-Port": "443",
+          "X-Forwarded-Proto": "https",
+          "tEsT-HEADeR": "aValUE"
+        },
+        "httpMethod": "GET",
+        "isBase64Encoded": false,
+        "multiValueHeaders": {
+          "Accept": [
+            "*/*"
+          ],
+          "Accept-Encoding": [
+            "gzip, deflate"
+          ],
+          "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-ASN": [
+            "<cloudfront-asn:1>"
+          ],
+          "CloudFront-Viewer-Country": [
+            "<cloudfront-country:1>"
+          ],
+          "Host": [
+            "<id:1>.execute-api.<region>.amazonaws.com"
+          ],
+          "User-Agent": [
+            "python-requests/testing"
+          ],
+          "Via": [
+            "<via:2>"
+          ],
+          "X-Amz-Cf-Id": [
+            "<cf-id:2>"
+          ],
+          "X-Amzn-Trace-Id": [
+            "<trace-id:2>"
+          ],
+          "X-Forwarded-For": [
+            "<source-ip:1>, <ip>"
+          ],
+          "X-Forwarded-Port": [
+            "443"
+          ],
+          "X-Forwarded-Proto": [
+            "https"
+          ],
+          "tEsT-HEADeR": [
+            "aValUE"
+          ]
+        },
+        "multiValueQueryStringParameters": null,
+        "path": "/test-path/",
+        "pathParameters": null,
+        "queryStringParameters": null,
+        "requestContext": {
+          "accountId": "111111111111",
+          "apiId": "<id:1>",
+          "domainName": "<id:1>.execute-api.<region>.amazonaws.com",
+          "domainPrefix": "<id:1>",
+          "extendedRequestId": "<extended-request-id:2>",
+          "httpMethod": "GET",
+          "identity": {
+            "accessKey": null,
+            "accountId": null,
+            "caller": null,
+            "cognitoAuthenticationProvider": null,
+            "cognitoAuthenticationType": null,
+            "cognitoIdentityId": null,
+            "cognitoIdentityPoolId": null,
+            "principalOrgId": null,
+            "sourceIp": "<source-ip:1>",
+            "user": null,
+            "userAgent": "python-requests/testing",
+            "userArn": null
+          },
+          "path": "/test/test-path/",
+          "protocol": "HTTP/1.1",
+          "requestId": "<uuid:2>",
+          "requestTime": "<request-time>",
+          "requestTimeEpoch": "<request-time-epoch>",
+          "resourceId": "<resource-id:1>",
+          "resourcePath": "/test-path",
+          "stage": "test"
+        },
+        "resource": "/test-path",
+        "stageVariables": null
+      },
+      "invocation-payload-without-trailing-slash-and-query-params": {
+        "body": null,
+        "headers": {
+          "Accept": "*/*",
+          "Accept-Encoding": "gzip, deflate",
+          "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-ASN": "<cloudfront-asn:1>",
+          "CloudFront-Viewer-Country": "<cloudfront-country:1>",
+          "Host": "<id:1>.execute-api.<region>.amazonaws.com",
+          "User-Agent": "python-requests/testing",
+          "Via": "<via:3>",
+          "X-Amz-Cf-Id": "<cf-id:3>",
+          "X-Amzn-Trace-Id": "<trace-id:3>",
+          "X-Forwarded-For": "<source-ip:1>, <ip>",
+          "X-Forwarded-Port": "443",
+          "X-Forwarded-Proto": "https",
+          "tEsT-HEADeR": "aValUE"
+        },
+        "httpMethod": "GET",
+        "isBase64Encoded": false,
+        "multiValueHeaders": {
+          "Accept": [
+            "*/*"
+          ],
+          "Accept-Encoding": [
+            "gzip, deflate"
+          ],
+          "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-ASN": [
+            "<cloudfront-asn:1>"
+          ],
+          "CloudFront-Viewer-Country": [
+            "<cloudfront-country:1>"
+          ],
+          "Host": [
+            "<id:1>.execute-api.<region>.amazonaws.com"
+          ],
+          "User-Agent": [
+            "python-requests/testing"
+          ],
+          "Via": [
+            "<via:3>"
+          ],
+          "X-Amz-Cf-Id": [
+            "<cf-id:3>"
+          ],
+          "X-Amzn-Trace-Id": [
+            "<trace-id:3>"
+          ],
+          "X-Forwarded-For": [
+            "<source-ip:1>, <ip>"
+          ],
+          "X-Forwarded-Port": [
+            "443"
+          ],
+          "X-Forwarded-Proto": [
+            "https"
+          ],
+          "tEsT-HEADeR": [
+            "aValUE"
+          ]
+        },
+        "multiValueQueryStringParameters": {
+          "urlparam": [
+            "test"
+          ]
+        },
+        "path": "/test-path",
+        "pathParameters": null,
+        "queryStringParameters": {
+          "urlparam": "test"
+        },
+        "requestContext": {
+          "accountId": "111111111111",
+          "apiId": "<id:1>",
+          "domainName": "<id:1>.execute-api.<region>.amazonaws.com",
+          "domainPrefix": "<id:1>",
+          "extendedRequestId": "<extended-request-id:3>",
+          "httpMethod": "GET",
+          "identity": {
+            "accessKey": null,
+            "accountId": null,
+            "caller": null,
+            "cognitoAuthenticationProvider": null,
+            "cognitoAuthenticationType": null,
+            "cognitoIdentityId": null,
+            "cognitoIdentityPoolId": null,
+            "principalOrgId": null,
+            "sourceIp": "<source-ip:1>",
+            "user": null,
+            "userAgent": "python-requests/testing",
+            "userArn": null
+          },
+          "path": "/test/test-path",
+          "protocol": "HTTP/1.1",
+          "requestId": "<uuid:3>",
+          "requestTime": "<request-time>",
+          "requestTimeEpoch": "<request-time-epoch>",
+          "resourceId": "<resource-id:1>",
+          "resourcePath": "/test-path",
+          "stage": "test"
+        },
+        "resource": "/test-path",
+        "stageVariables": null
+      },
+      "invocation-payload-with-trailing-slash-and-query-params": {
+        "body": null,
+        "headers": {
+          "Accept": "*/*",
+          "Accept-Encoding": "gzip, deflate",
+          "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-ASN": "<cloudfront-asn:1>",
+          "CloudFront-Viewer-Country": "<cloudfront-country:1>",
+          "Host": "<id:1>.execute-api.<region>.amazonaws.com",
+          "User-Agent": "python-requests/testing",
+          "Via": "<via:4>",
+          "X-Amz-Cf-Id": "<cf-id:4>",
+          "X-Amzn-Trace-Id": "<trace-id:4>",
+          "X-Forwarded-For": "<source-ip:1>, <ip>",
+          "X-Forwarded-Port": "443",
+          "X-Forwarded-Proto": "https",
+          "tEsT-HEADeR": "aValUE"
+        },
+        "httpMethod": "GET",
+        "isBase64Encoded": false,
+        "multiValueHeaders": {
+          "Accept": [
+            "*/*"
+          ],
+          "Accept-Encoding": [
+            "gzip, deflate"
+          ],
+          "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-ASN": [
+            "<cloudfront-asn:1>"
+          ],
+          "CloudFront-Viewer-Country": [
+            "<cloudfront-country:1>"
+          ],
+          "Host": [
+            "<id:1>.execute-api.<region>.amazonaws.com"
+          ],
+          "User-Agent": [
+            "python-requests/testing"
+          ],
+          "Via": [
+            "<via:4>"
+          ],
+          "X-Amz-Cf-Id": [
+            "<cf-id:4>"
+          ],
+          "X-Amzn-Trace-Id": [
+            "<trace-id:4>"
+          ],
+          "X-Forwarded-For": [
+            "<source-ip:1>, <ip>"
+          ],
+          "X-Forwarded-Port": [
+            "443"
+          ],
+          "X-Forwarded-Proto": [
+            "https"
+          ],
+          "tEsT-HEADeR": [
+            "aValUE"
+          ]
+        },
+        "multiValueQueryStringParameters": {
+          "urlparam": [
+            "test"
+          ]
+        },
+        "path": "/test-path/",
+        "pathParameters": null,
+        "queryStringParameters": {
+          "urlparam": "test"
+        },
+        "requestContext": {
+          "accountId": "111111111111",
+          "apiId": "<id:1>",
+          "domainName": "<id:1>.execute-api.<region>.amazonaws.com",
+          "domainPrefix": "<id:1>",
+          "extendedRequestId": "<extended-request-id:4>",
+          "httpMethod": "GET",
+          "identity": {
+            "accessKey": null,
+            "accountId": null,
+            "caller": null,
+            "cognitoAuthenticationProvider": null,
+            "cognitoAuthenticationType": null,
+            "cognitoIdentityId": null,
+            "cognitoIdentityPoolId": null,
+            "principalOrgId": null,
+            "sourceIp": "<source-ip:1>",
+            "user": null,
+            "userAgent": "python-requests/testing",
+            "userArn": null
+          },
+          "path": "/test/test-path/",
+          "protocol": "HTTP/1.1",
+          "requestId": "<uuid:4>",
+          "requestTime": "<request-time>",
+          "requestTimeEpoch": "<request-time-epoch>",
+          "resourceId": "<resource-id:1>",
+          "resourcePath": "/test-path",
+          "stage": "test"
+        },
+        "resource": "/test-path",
+        "stageVariables": null
+      }
+    }
+  }
+}