I am using Pulumi to create an AWS API Gateway that proxies to a Lambda backend. The API is used by a web frontend, and my Lambda Function handles CORS in most situations. However, if the Usage Plan for my API key is exceeded, the Gateway sends a 429 without any CORS headers, so the web frontend can't accurately determine the problem. What I would like is for the page to be able to display a dedicated "Server is overloaded" error when the Usage Plan quota is exceeded instead of just a generic "something went wrong."
I realize that I can enable CORS on the Gateway, but it looks like I can only do that manually via the console, and I want to use Pulumi exclusively.
I see that this answer says to use a Gateway Response, and it links to this answer that additionally emphasizes to "Make sure to re-deploy your gateway."
I created Gateway Responses that included the headers like this:
addGatewayResponse(restApi.api.id, "429", "QUOTA_EXCEEDED");
addGatewayResponse(restApi.api.id, "429", "THROTTLED");
addGatewayResponse(restApi.api.id, "403", "INVALID_API_KEY");
addGatewayResponse(restApi.api.id, "403", "MISSING_AUTHENTICATION_TOKEN");
addGatewayResponse(restApi.api.id, "404", "RESOURCE_NOT_FOUND");
addGatewayResponse(restApi.api.id, "400", "DEFAULT_4XX");
addGatewayResponse(restApi.api.id, "500", "DEFAULT_5XX");
function addGatewayResponse(
restApiId: pulumi.Output<string>,
statusCode: string,
responseType: string
) {
new aws.apigateway.Response(`${name}-GatewayResponse-${responseType}`, {
restApiId: api.api.id,
responseType,
statusCode,
responseTemplates: {
"application/json": JSON.stringify({
message: "$context.error.messageString",
type: "$context.error.responseType",
statusCode,
resourcePath: "$context.resourcePath",
}),
},
responseParameters: {
"gatewayresponse.header.Access-Control-Allow-Origin": "'*'",
"gatewayresponse.header.Access-Control-Allow-Headers": "'*'",
"gatewayresponse.header.Access-Control-Allow-Methods": "'*'",
},
});
}
and I completely destroyed and recreated my stack. I can log into the console and see that my Access-Control-Allow-*
headers and the template/parameters are configured on the Gateway Response for all the response types the way I expect.
However, when I try to test this using curl (by either omitting the api key, or manually setting the quota to a low number) I just get a standard response with no CORS headers:
< HTTP/2 429
< date: Thu, 27 Oct 2022 22:30:31 GMT
< content-type: application/json
< content-length: 28
< x-amzn-requestid: xxx
< x-amzn-errortype: LimitExceededException
< x-amz-apigw-id: xxx
<
* Connection #0 to host xxx.execute-api.xxx.amazonaws.com left intact
{"message":"Limit Exceeded"}
When I test via the web app, fetch
throws an error (TypeError: NetworkError when attempting to fetch resource.
) and my JavaScript does not have access to the response status code (as far as I can tell).
I am hitting the stage's invoke URL directly (bypassing any domain) and I tried making the gateway regional instead of edge optimized to (I think) avoid having Cloudfront in the middle.
If I provide the API key and set a normal quota, everything works fine.
So it seems like my Gateway Response configuration is just...not being used at all?
What am I missing?