aws-powertools / powertools-lambda

MIT No Attribution
73 stars 4 forks source link

feature(apigateway): define function to handle not found requests #65

Closed rtcnerd closed 2 years ago

rtcnerd commented 2 years ago

Executing the following code does not trigger the rules. Ideally I would expect the rule="/not-found-error" to be triggered when an incorrect path is sent. The print statement is never printed. I get the default value. Am I missing something?

from aws_lambda_powertools import Logger, Tracer from aws_lambda_powertools.logging import correlation_paths from aws_lambda_powertools.event_handler.api_gateway import ApiGatewayResolver from aws_lambda_powertools.event_handler.exceptions import ( BadRequestError, InternalServerError, NotFoundError, ServiceError, UnauthorizedError, )

tracer = Tracer() logger = Logger()

app = ApiGatewayResolver()

@app.get(rule="/bad-request-error") def bad_request_error():

HTTP 400

raise BadRequestError("Missing required parameter")

@app.get(rule="/unauthorized-error") def unauthorized_error():

HTTP 401

raise UnauthorizedError("Unauthorized")

@app.get(rule="/not-found-error") def not_found_error():

HTTP 404

print("Not found")
raise NotFoundError

@app.get(rule="/internal-server-error") def internal_server_error():

HTTP 500

raise InternalServerError("Internal server error")

@app.get(rule="/service-error", cors=True) def service_error(): raise ServiceError(502, "Something went wrong!")

alternatively

# from http import HTTPStatus
# raise ServiceError(HTTPStatus.BAD_GATEWAY.value, "Something went wrong)

def handler(event, context): return app.resolve(event, context)

boring-cyborg[bot] commented 2 years ago

Thanks for opening your first issue here! We'll come back to you as soon as we can.

heitorlessa commented 2 years ago

Hey @rtcnerd, thanks for raising this with us.

Routes are exact matches or regex patterns. This means, that print statement will only execute if an incoming request matches that route "/not-found-error".

There is an issue/PR to add support for handling 404s and the likes.

If there's a particular UX you'd like us to provide please do let us know!

rtcnerd commented 2 years ago

@heitorlessa what is the best way to handle 404 event and send back a custom message?

heitorlessa commented 2 years ago

@heitorlessa what is the best way to handle 404 event and send back a custom message?

Within your Lambda Handler, inspect the response from "app.resolve(event, context)" and see if "statusCode" is 404.

By default, docs suggest to simply "return app.resolve(event, context)".

At least until we provide a more streamlined way like "@app.not_found" and "@app.exception_handler()"

jakebrinkmann commented 2 years ago

🤔 hmmm, too bad there isn't a way to override the serializer in ApiGatewayResolver for errors

https://github.com/awslabs/aws-lambda-powertools-python/blob/be6e722e3d552c56ef916c87dffeb40e394fe499/aws_lambda_powertools/event_handler/api_gateway.py#L612-L617

edit: this is what I will do for now:

    try:
        response = app.resolve(event, context)

    except Exception:
        response = {
            "statusCode": 500,
            "message": {
                "type": "https://datatracker.ietf.org/doc/html/rfc7807",
                "title": "Internal Server Error",
                "detail": "An unexpected error has occurred",
                "status": 500,
            },
        }

    if response["statusCode"] >= 400:
        return Response(
            status_code=response["statusCode"],
            content_type="application/problem+json",
            body=response["message"],
        )
heitorlessa commented 2 years ago

There’s a WIP PR for it for the next release, Jake ;-)

On Tue, 14 Dec 2021 at 21:44, Jake Brinkmann @.***> wrote:

🤔 hmmm, too bad there isn't a way to override the serializer in ApiGatewayResolver for errors

https://github.com/awslabs/aws-lambda-powertools-python/blob/be6e722e3d552c56ef916c87dffeb40e394fe499/aws_lambda_powertools/event_handler/api_gateway.py#L612-L617

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/awslabs/aws-lambda-powertools-python/issues/884#issuecomment-993974406, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAZPQBFMCQUUVCFNAZ6E6YTUQ6UD5ANCNFSM5JZDORAQ .

heitorlessa commented 2 years ago

EDIT: Correct syntax error on @app.not_found

Done - it'll be available as part of today's release. Both not found and any exception you want to handle

app = ApiGatewayResolver()
logger = Logger()

@app.exception_handler(SomeKindOfError)
def handle_error(ex: SomeKindOfError):
   print(f"request path is '{app.current_event.path}'")
   return Response(status_code=418, content_type=content_types.TEXT_HTML, body=str(ex))

@app.not_found
def handle_not_found(exc: NotFoundError):
    return Response(status_code=404, content_type=content_types.TEXT_PLAIN, body="I am a teapot!")

@app.exception_handler(ServiceError)
def service_error(ex: ServiceError):
    logger.debug(f"Log out sensitive stuff: {ex.msg}")
    return Response(
        status_code=ex.status_code,
        content_type=content_types.APPLICATION_JSON,
        body="CUSTOM ERROR FORMAT",
    )

@app.get("/my/path")
def call_with_error() -> Response:
   raise SomeKindOfError("Foo!")

@app.get("/my/path2")
def call_with_error_sensitive() -> Response:
   raise InternalServiceError("Foo!")

def lambda_handler(event, context):
   return app(event, context)
heitorlessa commented 2 years ago

hey @rtcnerd this is now available as part of today's 1.23.0 release :) Thank you again for this feature request!

rtcnerd commented 2 years ago

@heitorlessa many thanks for introducing the new feature. However when I try executing your sample code on aws, i get the following error for not found: [ERROR] TypeError: not_found() missing 1 required positional argument: 'func' Traceback (most recent call last): File "/var/lang/lib/python3.9/importlib/init.py", line 127, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "", line 1030, in _gcd_import File "", line 1007, in _find_and_load File "", line 986, in _find_and_load_unlocked File "", line 680, in _load_unlocked File "", line 850, in exec_module File "", line 228, in _call_with_frames_removed File "/var/task/lambda_function.py", line 19, in @app.not_found()

heitorlessa commented 2 years ago

@heitorlessa many thanks for introducing the new feature. However when I try executing your sample code on aws, i get the following error for not found:

[ERROR] TypeError: not_found() missing 1 required positional argument: 'func'

Traceback (most recent call last):

File "/var/lang/lib/python3.9/importlib/init.py", line 127, in import_module

return _bootstrap._gcd_import(name[level:], package, level)

File "", line 1030, in _gcd_import

File "", line 1007, in _find_and_load

File "", line 986, in _find_and_load_unlocked

File "", line 680, in _load_unlocked

File "", line 850, in exec_module

File "", line 228, in _call_with_frames_removed

File "/var/task/lambda_function.py", line 19, in

@app.not_found()

🤦‍♂️ there's a syntax error in my comment up there - () - decorator should be @app.not_found not @app.not_found() or else you'll get the error you've got, my apologies.

The official docs are correct

https://awslabs.github.io/aws-lambda-powertools-python/latest/core/event_handler/api_gateway/#handling-not-found-routes

Let me know if you're still experiencing the same issue with the correct sample

michaelbrewer commented 2 years ago

@heitorlessa - should i accept @app.not_found() has well? just to safe?

michaelbrewer commented 2 years ago

@heitorlessa @rtcnerd - sorry about the errors with () I have added support for that too:

michaelbrewer commented 2 years ago

@rtcnerd - anything else missing from this?