Enabling Compression for Lambda with AWS HTTP APIs
AWS HTTP APIs provides a new way to deploy REST-based APIs in AWS; providing a number of simplifications over the original REST APIs.
However, when working with HTTP APIs we need to be aware of a few gotchas, such as what types to use for handler arguments. REST APIs also used to provide a way to enable payload compression. For HTTP APIs though, we need to compress the payloads ourselves.
Thankfully, this is relatively straightforward and I will explain each step required in the below. For those looking for a quick solution, I’ve created a library lambda-compression, you can use as follows.
Compress with Library
The lambda-compression library provides only one method compress
that accepts the event
variable that is passed into handler functions by the HTTP API and a ‘structured’ result (see Lambda function response for format 2.0).
The compress
function will return a structured result that can returned as the result of the handler function.
The library can be installed as a Node dependency:
npm i lambda-compression
yarn add lambda-compression
Here an example implementation using JavaScript:
import { compress } from 'lambda-compression';
export const handler = async (event, context) => {
return compress(event, {
statusCode: 201,
headers: {
'Content-Type': 'application/json',
},
body: '{"data":"hello"}',
});
};
And here an example implementation using TypeScript:
import { compress } from 'lambda-compression';
import {
Handler,
APIGatewayProxyEventV2,
APIGatewayProxyResultV2,
} from 'aws-lambda';
type ProxyHandler = Handler<APIGatewayProxyEventV2, APIGatewayProxyResultV2>;
export const handler: ProxyHandler = async (event, context) => {
return compress(event, {
statusCode: 201,
headers: {
'Content-Type': 'application/json',
},
body: '{"data":"hello"}',
});
};
Steps required for Compression
The logic required for implementing compression is quite simple since we can rely on the zlib
package provided in Node.js.
See a full source code example here: lambdaCompression.ts
Essentially we need to:
- Determine which compression formats the client accepts by querying the
accept-encoding
header. - If the client does not support compression, return the uncompressed payload.
- If the client does support compression:
- apply the supported compression format (
br
,gzip
ordeflate
), - Base64 encode the result,
- set the
isBase64Encoded
property in the result, and - set the Base64 encoded result as the
body
of the returned response.
- apply the supported compression format (
Final Thoughts
Compression can be CPU intensive, thus it could be prudent to cache the compressed results if the same result can be expected to be returned repeatedly. It is also possible to place your API behind a CloudFront Distribution that can take care of compressing payloads under limited circumstances. Lastly, reverting back to using a REST API also enables to use a built-in compression function.
If you have any ideas of improving the library, please be welcome to submit an issue 🤗.
Cover image by iam_os.