How to Mimic Flask’s Error Handling When Using AWS Lambda
In this basic Flask app, we get the county name and return the corresponding “Hello from” greeting message:
One of the errors we need to handle in this example is when the request is missing one of its required arguments, the country_name
argument.
For this kind of error, we would like to return the 400 status code (Bad Request) as the error code, and a custom response message. The response message should indicate that the country_name
argument is missing.
When using Flask, we:
- Create a function to handle each type of error.
We create thehandle_key_error
function that receives the error, extract the missing argument name and error code, and builds and returns the corresponding response. - Decorate the function with Flask’s
errorhandler
decorator.
Flask’serrorhandler
decorator is responsible to catch all the exceptions that are raised in a specific code or exception class. The exception class or code is passed to the decorator as its argument.
In our case, Flask will raiseBadRequestKeyError
when a key error is missing in the request, so we create the decorator withBadRequestKeyError
.
We can add as many error handling functions as needed, and wrap each with its matching error handling decorators, one for each exception classes or codes. Each function is responsible to handle the error and can log or inform any relevant external system, etc.
To make sure we don’t leave any exception uncaught, it is recommended to always add a function to catch all the unexpected exceptions, using the Exception
parent exception class as the errorhandler
decorator argument.
When using Flask’s error handling we are keeping our code clean, having one place with the “core” code and another, separated, who is responsible for all the error handling.
When using AWS Lambda we need to create an entrypoint function with the def handler(event, context)
signature. This function will be called in each invocation of the Lambda, and will contain the request in the event
argument.
In this case, as we don’t have any error handeling statments to catch our errors, so every exception will cause our code to exit and our Lambda to crash.
To catch those exceptions, we will create a handle_errors
function.
Inside this function, we will create another function, safe_execute_func
that will be responsible to safely execute the original call function func
(which in our case is the handle
) and catch and handle any exception raised from it.
The safe_execute_func
decorator gets the general arguments, *args
and **kwargs
and contains a try
and except
block. In the try block, it will call the wraped function func
. In the except block, it will catch the exceptions and create the custom response for each type of exception caught.
will use the functools.wraps
decorator to make sure that the wrapped function has the same function name, docstring, arguments list, etc.
We will wrap the handler
function with our new decorator, the handle_errors
. Now, each run of thehandler
, safe_excute_func
will be executed instead and will handle all the errors internally.
The way Flask hides and isolates all the error handling using the errorhandler
decorator is elegant and neat. I tried to mimic this behavior when I started using AWS Lambda AWS Lamda and was forced to use the predefined handler
function.
Here I presented a decorator that handles the error handling for the Lambda function in one place, and thus helps keeping the “core” code clean and untouched.