Probably the most used, versatile and oldest combination between AWS cloud services is REST APIs (public) with Lambda integration on the backend . While RESTful API development is not at all new, if you are relatively new to developing in the cloud, working with these two services may be somewhat challenging. This article requires a basic understanding of these two services. Its focus is beyond the point where you are able to invoke a Lambda function and receive status code 200 from the API. Given the availability of SNS and CloudWatch Logs, why would one bother integrating the API Method & Integration Responses past returning code 200? The answer is that would be a half implemented feature, which lets users speculating about what the result of the invocation was. This article shows how to program an API to return status codes that make sense to your application.
My Use Case
I shall focus on a Lambda function which may throw unexpected exceptions, errors and return a response. To make this more challenging, I am going to use Python. This language is a big hit with developers transitioning from traditional scientific and engineering roles, who have not used any “JS” languages. The intention is to create a foundation on which further API development can be done or at least leave the API in a minimum viable state.
I started creating the Lambda function, which I called DanielHTTP. The function uses the latest Python runtime and the IAM policy
AWSLambdaBasicExecutionRole which allows CloudWatch logs to be created. I created a role called the same and attached the policy. Alternatively, when this function is created, I could have selected
Create New Role to have this done automatically. The function code is available in my GitHub repository . The code is designed to throw an exception by performing an illegal operation, to raise exceptions and errors and to return an Ok response. All cases are individually handled in the API.
It is a good idea to have a common design for the responses that I can easily control. Generally, I favor a two tier dictionary:
"context”refer to: a programmable HTTP status code , severity type (Exception, Error, Info, etc.), the actual message to be communicated and the context surrounding the response
"context"can contain anything I need to help out my users, including contextual data regarding the function invocation , in this case for Python
The RESTful API, also called DanielHTTP, uses a
guid resource with a
POST method. Next, I will show how this is assembled step-by-step.
GUID query string is defined in the method request in order to be able to select the various execution path in the Lambda function:
The Lambda function and region are specified in the integration request. I was prompted that the API has been given permissions to invoke the Lambda function. At this stage, API Gateway should show as a trigger on the Lambda function page.
A mapping template is defined in the integration request as shown below. This allows the Lambda function to receive parameter data according to the code requirements.
The method response contains a single definition for HTTP status code 200. This code will always be returned regardless of the code path in Lambda, which it not helpful. I set the response body as indicated below.
Next, I defined code 400 for Errors and code 502 for Exceptions, returned by the function. The response body is identical in both cases.
The last step is to define the integration response . During this phase of the API invocation the response from the Lambda is compared against the
selectionPattern defined as a regex, then mapped to the defined method response status. The default mapping to status 200 is processed last, because such a selection pattern will match all error messages, including null, i.e., any unspecified error message.
Both the integration response mapped to code 400 and the one mapped to code 502, have the same mapping template definition as shown below. This allows the API to extract the value of
"errorMessage" key in the returned dictionary from Lambda. I needed to save both the mapping template and the actual mapping.
The mapping template definition for code 200, allows the API to override the 200 code. Code 500 is returned instead, if the function response contains the word
stackTrace. Again, I needed to save save twice.
I could have skipped all these steps by importing the API from my repository . Instructions are provided.
I finalized API development by deploying it from the Actions Button > Deploy API. I named my stage
My API Invocation
I retrieved the invoke URL by selecting the
prod Stage from the Stages Section. The first invocation selects the path where illegal code is found. As the illegal code is executed an unhandled exception is raised.
At runtime, API Gateway matches the Lambda error’s
errorMessage against the pattern of the regular expression on the
selectionPattern property. If there is a match, API Gateway returns the Lambda error as an HTTP response of the corresponding HTTP status code. If there is no match, API Gateway returns the error as a default response or throws an invalid configuration exception if no default response is configured .
In the unhandled exception case above, neither
Exception were found in the value corresponding to the
errorMessage key. Therefore, this is matched against the 200 code. This is not an Ok answer but one can always count on a stack trace being part of an exception, which is the case here. Therefore, code 500 is returned instead because of the overriding caused by finding
stackTrace in the response .
The second and third invocations select the code paths where exceptions are raised by the developer. It is not possible to mimic the
errorMessage response to get an error. The Lambda function must fail according to the runtime used. In Python, the
raise Exception()does the job. The mapping template is used to discard the
stackTrace keys, which are created when an exception is raised. Only the actual coded response is passed as serialized JSON string and assigned to the
errorMessage key. The
Exception words and returns the appropriate HTTP code.
The forth and final invocation covers the code path which returns a value when everything is Ok . The returned value is passed as a JSON object. Nothing is matched and code 200 is the method response.
Finally, I hope you enjoyed reading this and widened your understanding of integrating API Gateway — Lambda responses.