API Gateway Regional vs. Edge-Optimized Endpoints

API Gateway recently launched regional endpoints, a deceivingly simple feature that has important implications:

  • lower latency for clients located in the same AWS region (i.e. running in EC2 or Lambda)
  • ability to manage your own CloudFront distribution or WAF for your API
  • ability to manage DNS routing for your custom domain name

In my opinion, the biggest win here is the ability to integrate Route53 DNS routing with your REST APIs. If you replicate your APIs to multiple regions (using OpenAPI import, for example), you can take advantage of powerful Route53 features such as latency-based routing, regional failover, and blue green deployments.

There are distinct advantages for both options. Here’s my personal take on when to use each:

When to use regional endpoints:

  • your clients are predominantly located in the same AWS regions (i.e. running in EC2 or Lambda)
  • you want to manage your own CloudFront distribution and use CloudFront features such as custom routing rules, edge caching, WAF, Lambda@Edge, etc
  • you want to take advantage of DNS routing for your custom domain name

When to use edge-optimized endpoints:

  • You have geographically distributed clients
  • You don’t want to pay for and manage your own CloudFront distribution

A note on latency benchmarking:

A common pattern I’ve seen is for developers to conduct performance tests against API Gateway with traffic originating from a single EC2 region, or worse, from a single development machine. These types of tests will likely produce better latency results using regional endpoints. However, keep in mind that if you have geographically distributed clients, synthetic tests will not represent the client experience. The best way to truly measure this is to track client-side latency metrics from your API clients.

Congrats to the API Gateway team on a very important release.

Cheers,

Ryan

Generic Amazon API Gateway Java Client (SDK)

I’ve recently released apigateway-generic-java-sdk, a simple generic Java client for Amazon API Gateway endpoints for those that don’t necessarily want to generate a strongly-typed SDK. This is particularly useful when the API definition is changing rapidly or when you don’t want to go through the effort of generating and bundling an SDK, such as when prototyping or scripting.

It is optimized to run from a Lambda function and does not require any extra dependencies beyond the AWS SDK, which is already bundled in the Lambda runtime.

Features

  • AWS SigV4 request signing. Supports APIs authenticated with IAM auth using standard AWSCredentialsProvider interface
  • API Keys
  • Custom headers
  • Throws exceptions for non-2xx response codes
  • Compatibility with existing AWS SDK client configuration (connections, retry policies, etc)
  • Runs in AWS Lambda functions with no additional dependencies

Example

To get the code and for more examples, see the GitHub repo.

How to send response headers for AWS Lambda function exceptions in API Gateway

In a previous post on error handling in API Gateway I discussed various ways to map errors from your Lambda function to appropriate API status codes and how to build the response body appropriately for different types of errors.

One common pattern we’ve seen come up is the requirement to return a specific response header value depending on the type of error from the Lambda function. While this is most easily achieved with proxy integrations, some prefer to use the explicitly-mapped “AWS” integration type. This allows their Lambda function implementation to use native error types and decouples it from their API Gateway configuration.

In this example I will show how to manipulate the HTTP status code, the response body, as well as a response header value based on the Lambda error outcome.

Note, this example is specific to the NodeJS runtime, and will only allow to set a single header – please post in the comments if you have similar solutions for other runtimes.

This technique makes use of the fact that Lambda serializes the exception type in the errorType field, which can be mapped to a header value in API Gateway. This is a workaround solution until API Gateway supports JSON-parsing in parameter mapping expressions.

Lambda function

Observe that this Lambda function sets the error.name field to the value desired in the response header. When the error is serialized by Lambda, this becomes the “errorType” field in the Lambda response. You can also set custom properties in the Lambda error which can be used when rendering the API response body.

This Lambda function outputs the following response:

API definition

Note that the method response header is set to the value of the “errorType” field in the Lambda error response for 400 responses.

Zooming in on the mapping template for the 400 response:

The “stringified” errorMessage is parsed by the mapping template so that all properties (including custom properties) of the error object can be accessed in the mapping template to build the response body.

Invoking this method produces the following results, appropriately setting the trifecta of status code, response body, and response header.

Comments, questions, and improvements are welcome!

-Ryan

Bare-bones Swagger Example for API Gateway Simplified Proxy Features

Amazon API Gateway just made it a LOT easier to build an API to front an existing HTTP backend or Lambda functions.

Recent additions of a few simple but powerful new features reduce the amount of configuration needed to build an API Gateway proxy by several times. No more mapping templates, parameter mapping, response mappings, etc. (unless you need them).

Here’s a super simple example demonstrating the 3 new features (greedy path parameter, “ANY” method, and proxy integration types).

This API will accept requests using any HTTP method to any subpath of any depth under either /http or /lambda. Any request under /http will proxy all headers, path parameters, and query string parameters to the HTTP integration (httpbin.org). Any request under /lambda will invoke a Lambda function with complete API request data in accordance with the proxy convention defined here.

Easy API Gateway/Lambda “Serverless” API Logging/Debugging

Developing and testing “serverless” APIs using Amazon API Gateway and AWS Lambda can be made much easier with built-in support for CloudWatch Logs.

In Lambda functions you can use log statements to send log events to CloudWatch Log streams, and API Gateway automatically submits log events for requests to APIs with logging enabled.

However, it can be difficult to reconcile log events for a serverless API sent across multiple CloudWatch log groups and log streams. Tracking down logs for a specific request or tailing request logs for a serverless API can be a cumbersome experience.

To help improve the serverless dev/debug/test experience, I’ve released a fork of the excellent awslogs project to include native support for API Gateway/Lambda serverless APIs. Given an API Gateway REST API ID and Stage name, this tool produces an aggregated stream of time-ordered*, color-coded log events emitted by API Gateway and all Lambda functions attached to your API. The log events can then be further filtered and processed by standard command-line tools.

i.e. stream all log events emitted from API Gateway as well as from all Lambda functions attached to the API:

or search APIG/Lambda logs for events from a specific request ID in the past hour:

Tip: To correlate API Gateway request IDs with Lambda invocations, send $context.requestId to your Lambda function via a mapping template and include it in your Lambda log messages (i.e. console.log(event.apiRequestId + ” – log message”);)

Check out ‘apilogs’ here. Fixes and contributions are greatly appreciated.

Happy debugging!
Ryan

An API Gateway mapping template to “send everything” to your Lambda function

If you’re trying to get up to speed with developing microservices on API Gateway and Lambda, one of the first things you will want to try is to send basic API request data to your Lambda function.

Since all Lambda function input data must go in the request body, you must use an API Gateway mapping template to build a JSON representation of your data.

Here’s a master template to “send everything” API Gateway provides (as of 02/22/2016) to your Lambda function. This should serve as a good starting point and can be modified to suit your use-case. This will include all HTTP parameters, context data, stage variables, and the full method request body.

Here’s a Gist with the code.

For more information, check out the API Gateway mapping template reference.

Cheers,

Ryan

How To: HTTP redirects with API Gateway and Lambda

Update (2017-08-15): Recent service updates have removed the need for the workarounds described below, though they may still be useful in some cases, or for historical context.

Achieving HTTP redirects with API Gateway and Lambda is now trivial with the addition of Proxy integrations.

Simply define an API with an ‘aws_proxy’ integration type, and implement your Lambda function to explicitly return the redirect status code and Location header.

Lambda Function

i.e.

Swagger

——

API Gateway recently released support for mapping response bodies to response headers. One application of this feature is to enable conditional HTTP redirects in your API Gateway/Lambda API.

There are a couple of ways to achieve 30x redirects in your API Gateway/Lambda API.

Option 1: 30X as “default” response

This option is preferred if your API method always redirects (i.e. never returns a normal 2XX response).

1) Define a method response with status 302, and a “Location” header defined
2) Define a “default” integration response mapping with blank regex, mapping to 302.
3) For this response, define a “Location” header mapping from the redirect URL returned in your Lambda function. i.e. “integration.response.body.location”
3) Configure your lambda function to return the redirect location in the body, i.e.

Swagger example

Lambda function

Option 2: 30X as an error response

This option allows your method to return both “successful” (2XX) and redirect outcomes, but requires you to model redirects in your lambda function as errors.

1) Define a method response with status 302, and a “Location” header defined. Leave the “default” integration 2XX response with blank regex, mapped to your 2XX method response.
2) Define the redirect integration response mapping with regex “http.*”, mapped to your 30X response.
3) For this response, map the redirect URL returned in the error message of your lambda function to your “Location” header: “integration.response.body.errorMessage”
3) Configure your lambda function to return the redirect location as the error message, i.e.

or

4) Optional: If you don’t want to expose the lambda error response body to the client, define a mapping template on the redirect response to nullify the response body. You can use a template with a comment to render an empty response.

Swagger example

Lambda function

Here’s a full Gist with the example.

Cheers,
Ryan

Sending all HTTP parameters in API Gateway

Here’s an API Gateway mapping template to send all HTTP path, query string, and header parameters to your backend integration (i.e. Lambda function).

will produce something like:

The parameters can then be accessed in your Lambda function, i.e.

Here’s a Gist with the example.

Cheers,
Ryan