Serverlessconf NYC just wrapped up, and it was excellent. In my talk on the state of serverless and event-driven programming, I made a short digression to malign the API Gateway Lambda proxy integration.
In retrospect, I don’t think I was clear enough about what the features are and what I’m recommending against.
The pattern that I am recommending against is the “API Gateway proxy integration” as shown in the API Gateway documentation here. It involves three separate features:
- Greedy path variables: route multiple paths to a single integration
- The ANY method: route any HTTP method to the integration
- The Lambda proxy integration itself: instead of defining a transform from the web request to the Lambda input, and from the Lambda output to the web response, use a standard way of passing the request and response to and from the Lambda.
When these three features are put together, it can turn API Gateway into a passthrough, letting you use your favorite web framework in a single Lambda to do all your routing and processing. Great, right?
There are several problems with this approach:
- Your Lambda gets bloated with all the code for multiple logical paths
- You’ve increased your attack surface by allowing more requests through API Gateway into your own code and by relying on additional 3rd party libraries — whose security you are responsible for
- You’re paying for your Lambda to run logic that API Gateway will do for free
- You’re missing out on the API documentation features that API Gateway provides
Recommendations for using API Gateway
However, the Lambda proxy integration itself is not that bad! It skips the transform step, which can decouple your Lambda from any HTTP-related notions, but this is only useful if you plan for your Lambda to be invoked from other sources.
If you don’t use it with greedy path variables or the ANY method, and use request models to provide request validation, then you’ll have lean, single-task Lambda functions that can make strong assumptions about the content of their input.
To sum up: keep as much web logic in API Gateway as possible, because it’s free and visible/documented there, versus opaque, billed to you, and your security responsibility when it’s in your code.
However, if your Lambda is only ever invoked by API Gateway, use the proxy integration with these guidelines:
- Avoid greedy path variables, except perhaps for a catch-all 404.
- Avoid using the ANY method.
- Define request models and enable request validation (remember it’s off by default).
- In your Lambda, check that the content-type header matches one of your request models, and return a 415 Unsupported Media Type status code if it doesn’t (the proxy integration uses the WHEN_NO_MATCH passthrough behavior). After this check, your Lambda can assume the request validation is fully enforced.
HOWEVER: if you’re just starting with serverless, the proxy integration is a great way to get off the ground, or to bring existing code into Lambda to reap the benefits of not paying for idle resources.
Just be aware of the downsides, and know that you should grow out of it at some point. I mentioned this in my talk; thanks to Alex DeBrie for pointing out that I didn’t include it here at first.
Thanks to Preston Tamkin for his help in nailing down the exact behavior of the proxy integration.