AWS Compute Blog
Redirection in a Serverless API with AWS Lambda and Amazon API Gateway
Ronald Widha @ronaldwidha
Partner Solutions Architect
Redirection is neither a success nor an error response. You return redirection when the requested resource resides either temporarily or permanently under a different URI. The client needs to issue subsequent calls to the new location in order to retrieve the requested resource. Even though you typically see 302 and 301 redirects when requesting text/html, these response types also apply to REST JSON endpoints.
Many of you are already familiar how to return success and error responses. Amazon API Gateway and AWS Lambda help development teams to build scalable web endpoints very quickly. In a previous post (Error Handling Patterns in Amazon API Gateway and AWS Lambda), we discussed several error handling patterns to implement an explicit contract for the types of error responses that an API can produce and how they translate into HTTP status codes. However, so far this blog has not discussed how to handle redirection.
This post shows the recommended patterns for handling redirection in your serverless API built on API Gateway and Lambda.
Routing Lambda errors to API Gateway HTTP 30x responses
In HTTP, there are several types of redirection codes. You return these status codes as part of an HTTP response to the client.
Type | HTTP Status Code | Description |
---|---|---|
Multiple types available | 300 | The requested resource is available in multiple representations with its own specific location (not commonly used). |
Moved permanently | 301 | The requested resource has been moved a new permanent URI. |
Found | 302 | The requested resource is temporarily available under a different URI. |
For more information about HTTP server status codes, see RFC2616 section 10.5 on the W3C website.
In this specific scenario, you would like your API Gateway method to return the following HTTP response. Note that there are two key parameters to return:
- The status code, i.e., 301 or 302
- The new URI of the resource
HTTP/1.1 302 Found
Content-Type: text/html
Content-Length: 503
Connection: keep-alive
Date: Fri, 08 Jul 2016 16:16:44 GMT
Location: http://www.amazon.com/
In API Gateway, AWS recommends that you model the various HTTP response types that your API method may produce, and define a mapping from the return value of your Lambda function to these HTTP responses. To do that, you need to do two things:
- API Gateway can only map responses to different method responses on error. So even though redirection isn’t strictly a failure, you still throw an exception from Lambda to communicate back to API Gateway when it needs to issue a 30x response.
- Unlike HTTP 200 Success or any of the HTTP Error status codes, a redirection requires two values: the status code and the location. API Gateway do not support VTL for JSON serialization in the header mappings; thus, in this case, you need to take advantage of how the Lambda runtime handles exceptions to pass these values in two separate fields back to API Gateway.
Node.JS: Using the exception name to store the redirection URI
The mapping from a Lambda function error to an API Gateway method response is defined by an integration response, which defines a selection pattern used to match the Lambda function errorMessage
and routes it to an associated method response. In this example, you use the prefix-based error handling pattern:
API Gateway Settings | Value |
---|---|
Integration Response: Lambda Error Regex | ^HandlerDemo.ResponseFound.* |
Method Response: HTTP Status | 302 |
Because you don’t have access to VTL in the API Gateway header mappings, retrieve your redirection URI from errorType
.
API Gateway Settings | Value |
---|---|
Integration Response: Header Mappings | Location: integration.response.body.errorType |
In the Lambda function Node.JS runtime, errorType
can be assigned to any value. In this case, use it to store the redirection URI. In the handler.js, you have the following:
// Returns 302 or 301
var err = new Error("HandlerDemo.ResponseFound Redirection: Resource found elsewhere");
err.name = "http://a-different-uri";
context.done(err, {});
The same technique applies to 301 permanent redirects except you replace the API Gateway regex above to detect HandlerDemo.MovedPermanently
.
Node.JS: Handling other response types
In order to keep it consistent, you can leverage the same pattern for other error codes. You can leverage errorType
for any end user–visible messages.
//404 error
var err = new Error(“HandlerDemo.ResponseNotFound: Resource not found.”);
err.name = “Sorry, we can't find what you're looking for. Are you sure the address is correct?";
context.done(err, {});
Just as an example, upon failure, you return a “Fail Whale” HTML webpage to the user.
API Gateway Settings | Value |
---|---|
Integration Response: Lambda Error Regex | ^HandlerDemo.ResponseNotFound.* |
Method Response: HTTP Status | 404 |
Integration Response: Content-Type (Body Mapping Templates) | text/html |
Integration Response: Template | <html> <img src=”fail-whale.gif” /> $input.path(‘$.errorType’) </html> |
HTTP 200 Success can be handled as you normally would in your handler.js:
//200 OK
context.done(null, response);
Java: Using the Java inner exception to store the redirection URI
Because Java is a strongly typed language, the errorType
Lambda function return value contains the Java exception type which you cannot override (nor should you). Thus, you will be using a different property to retrieve the redirection URI:
API Gateway Settings | Value |
---|---|
Method Response: HTTP Status | 302 |
Integration Response: Header Mappings | Location: integration.response.body.cause.errorMessage |
The cause.errorMessage
parameter is accessible in the Lambda function Java runtime as an inner exception.
throw new Exception(new ResponseFound("http://www.amazon.com"));
ResponseFound
is a class that extends Throwable
.
package HandlerDemo;
public class ResponseFound extends Throwable {
public ResponseFound(String uri) { super(uri); }
}
The full response from Lambda received by API Gateway is the following:
{
"errorMessage": "HandlerDemo.ResponseFound: http://www.amazon.com",
"errorType": "java.lang.Exception",
"stackTrace": [ ... ],
"cause": {
"errorMessage": "http://www.amazon.com",
"errorType": "HandlerDemo.ResponseFound",
"stackTrace": [ ... ]
}
}
Because Lambda serializes the inner exception type to the outer errorMessage
. you can still use the same Lambda error regex in API Gateway to detect a redirect from errorMessage
.
API Gateway Settings | Value |
---|---|
Integration Response: Lambda Error Regex | ^HandlerDemo.ResponseFound.* |
Conclusion
In this post, I showed how to emit different HTTP responses, including a redirect response, on Amazon API Gateway and AWS Lambda for Node.JS and Java runtimes. I encourage developers to wrap these patterns into a helper class where it handles the inner working of returning a success, error, or redirection response.
One thing you may notice missing is an example of handling redirection in Python. At the time of writing, the Chalice community is considering support for this use case as part of the framework.
If you have questions or suggestions, please comment below.