June 6th, 2017
How to use Amazon API Gateway {proxy+}
By Justin Iravani

Background

One of my favorite tools on AWS is API Gateway. I’ve used it to build several internal tools as well as labs for our trainings. If you haven’t used API Gateway, I suggest you start HERE.

Amazon’s API Gateway provides a relatively simple way to put an HTTP endpoint in front of your resources (both AWS and on-prem). API Gateway gives you a few different ways to define and handle the various pieces of your API’s HTTP resources:

  • Static Resource, which requires you to define every possible resource and method individually.
  •    For Example:
       •http://example.com/bikes/huffy
       •http://example.com/bikes/cannondale
       •http://example.com/wagons/radioflyer

  • The resource as a path variable, wherein the resource is passed to the backend as a variable, but sub-resources still need to be individually defined.
  •    For Example:
       •http://example.com/{category}/huffy
       •http://example.com/{category}/cannondale
       •http://example.com/{category}/radioflyer

  • Everything as a path variable, configuring your resource as a proxy resource or {proxy+} is a greedy path wherein the entire sub-resource chain is passed to your backend as path variables.
    (http://example.com/{proxy+} captures all of these sub-resources as path variables)
  •    For Example:
       •http://example.com/bikes/huffy/super-fast
       •http://example.com/bikes/cannondale/racing/street/cool-bike
       •http://example.com/wagon/radioflyer

  • Once the resource is defined you then must create HTTP methods; if you’re unfamiliar with standard HTTP methods/verbs, go HERE.

Another cool API Gateway feature is the ANY method which allows for a single method definition that enables you handle all HTTP methods. E.g. GET, POST, PUT, DELETE, etc. are all sent to the same backend resources.

Between {proxy+} and the ANY method you can define a single resource that can handle all of your API requests. This is very useful if you want your backend resource to handle all of the decision making, but you want to make use of API Gateway‘s features (scaling, throttling, authorization, request validation, https).

To use the greedy {proxy+} path:

  • Navigate to your API HERE.
  •    •Press Actions
       •Press Create Resource
       •Select Configure as proxy resource


       •Press Create Resource

  • Then create the appropriate ANY method:
  •    •Press Actions
       •Press Create Method
       •Select Use Lambda Proxy integration
       •Select Region
       •Select Lambda Function
       •Press Save

The primary difference between using a proxy resource and the other two resource types is the response for the entire integration response (proper headers/status codes/body). As such, your backend resource must return a properly formed response to the HTTP request (see API Gateway section below).

To a demonstrate how to use the {proxy+} resource, I came up with a fun example. I also wanted the ability to create a custom token so I could obfuscate long S3 urls and other random domains, but also have a name that made sense. Think of a serverless bit.ly clone (e.g. redirects tokens to a URL bit.ly/neat)

The serverless URL redirect tool consists of the services below:

API Gateway

  • API Gateway serves the website via proxy path /{proxy+}
  • When using proxy+, everything is passed to your backend resource (in this case, our Lambda function) as a JSON document including entire resource path (example.com/resource/subresource/subsubresource/), query string parameters, headers, etc.
{
    "body": "{\"test\":\"body\"}",
    "resource": "/{proxy+}",
    "requestContext": {
      ...
      "identity": {
        ...
      },
      "stage": "prod"
    },
    "queryStringParameters": {
      "foo": "bar"
    },
    "headers": {
      ...
    },
    "pathParameters": {
      "proxy": "path/to/resource"
    },
    "httpMethod": "POST",
    "path": "/path/to/resource"
}

When using a {proxy+} resource, API Gateway expects a specific return payload (seen below). If anything else is returned, API Gateway will return a 500 error and the logs will show a malformed Lambda response. Your code will need to formulate the proper status and headers based on what you’re trying to accomplish. In this case, the function returns a statusCode of 200 or 301 depending on whether or not a given token exists.

{
        "statusCode": 200 |301|4XX|5XX,
        "headers":{
          "Content-Type": "text/html",
          ...
        },
        "body": "..."
    }

Lambda

In this example use case, I’ve used Lambda to serve as both the front and back end of my redirect microservice. The GET method will serve up an HTML and JS front end. The POST handles the validation of the destination_url and the creation of a new entry DynamoDB.

You can view the code HERE.

Note: Although a simple use case, what I’ve written is actually more of a monolithic app or function. This makes it very easy to break the API and harder to test. From an architecture standpoint, it usually makes more sense to have a different function service each http method.

DynamoDB

For this example, I use a simple DynamoDB table with two fields:
id is a quasi-unique 6 digit token, which is used as part of the shortened URL https://…/redirect/ABC123.
destination_url contains the redirect URL.

Conclusion

API Gateway {proxy+} is a powerful tool to that can greatly simplify your front end API. Use it!

Deploy it for your own use

Cloudformation Template

SAM Template

There is currently a bug with SAM for proxy resources where it doesn’t properly provision API Gateway permissions to your Lambda function. To fix this, follow the steps below:

  • Press on the pencil icon next to the Lambda function:
  • Press the checkbox to the right of the Lambda function
  • A pop-up will prompt you to give API Gateway invocation permissions on your Lambda function. Press OK.