CDK pattern – API Gateway caching
API Gateway has built-in support for caching endpoint’s responses. So, we don’t have to set up CloudFront by ourselves.
Enable API Gateway caching
To enable caching, we need to use an edge optimized endpoint and set some values on the deployOptions
.
const api = new apigateway.RestApi(this, id, {
domainName: {
endpointType: apigateway.EndpointType.EDGE,
},
deployOptions: {
cachingEnabled: true,
cacheClusterEnabled: true,
cacheTtl: cdk.Duration.minutes(30),
},
});
Note that if we need to use a custom domain for our API the certificate needs to be in the us-east-1
.
To use an ACM certificate with an API Gateway edge-optimized custom domain name, you must request or import the certificate in the us-east-1 Region (US East (N. Virginia)). To enable caching with need to use an edge optimized endpoint.
We can now query our endpoint and check CloudWatch to check that we are hitting the cache.
Query string support
That works great until we start to use query strings. For instance, if we build an OEmbed API, we need to support url
and format
query strings. With the current setup, we will always get the same cached response when hitting the endpoint even if we change the url
value.
To fix that, we need to set up the request parameters to take the query strings into account.
const integration = new apigateway.LambdaIntegration(lambda, {
cacheKeyParameters: ['method.request.path.url', 'method.request.path.format'],
requestParameters: {
'integration.request.path.url': 'method.request.path.url',
'integration.request.path.format': 'method.request.path.format',
},
});
endpoint.addMethod('GET', integration, {
requestParameters: {
'method.request.path.url': true,
'method.request.path.format': true,
},
});
If you know a less verbose solution, please don’t hesitate to ping me on Mastodon.
All together solution
export class Stack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const lambda = new lambda.Function(this, 'SomeFunctionId', {
runtime: lambda.Runtime.NODEJS_12_X,
code: lambda.Code.fromAsset('functions/dist/handler'),
handler: 'index.handler',
});
const api = new apigateway.RestApi(this, id, {
domainName: {
endpointType: apigateway.EndpointType.EDGE,
},
deployOptions: {
cachingEnabled: true,
cacheClusterEnabled: true,
cacheTtl: cdk.Duration.minutes(30),
},
});
const v1 = api.root.addResource('v1');
const endpoint = v1.addResource('some-route');
const integration = new apigateway.LambdaIntegration(lambda, {
cacheKeyParameters: ['method.request.path.url', 'method.request.path.format'],
requestParameters: {
'integration.request.path.url': 'method.request.path.url',
'integration.request.path.format': 'method.request.path.format',
},
});
endpoint.addMethod('GET', integration, {
requestParameters: {
'method.request.path.url': true,
'method.request.path.format': true,
},
});
}
}