-
Notifications
You must be signed in to change notification settings - Fork 676
Description
I am pretty positive that the bug is on APIGW side of things, but I feel like this needs to be documented somehow.
Setup
- APIGW proxy-integrated with Lambda via
ANY
method - Custom domain
api.some-domain.com
is defined on top of APIGW(using APIGW console and not manually via Route53) - Lambda exposes a
GET /healthz
endpoint that returns a'OK'
string - APIGW is deployed to
v1
stage, so that the URL to invoke the/healthz
endpoint above ishttps://randomstring-execute-api-<region>.amazonaws.com/v1/healthz
Explanation
When custom domain api.some-domain.com
is defined using the default base path mapping (which is /
) to v1
stage, then both the random and custom domain URLs work:
https://api.some-domain.com/healthz
https://randomstring-execute-api-<region>.amazonaws.com/v1/healthz
which is the expected result.
However, when a non-default base path mapping is used (for example /custom
), then:
https://randomstring-execute-api-<region>.amazonaws.com/v1/healthz
continues to work (as it should), while neither of the following works (the first one should have worked):
https://api.some-domain.com/healthz
https://api.some-domain.com/online/healthz
https://api.some-domain.com/online/v1/healthz
Any other combination of the above doesn't work either.
Reason
After contacting AWS support and doing some testing, the reason is a difference in path resolution in two cases.
- When a default
/
base path mapping is used, the Lambda handler is passed the followingevent
structure (abridged to contain only relevant parts for clarity):
{
resource: '/{proxy+}',
path: '/healthz',
httpMethod: 'GET',
...
pathParameters: { proxy: 'healthz' },
stageVariables: { alias: 'v1' },
...
}
- When a non-default
/custom
base path mapping is used, the followingevent
structure is passed:
{
resource: '/{proxy+}',
path: '/custom/healthz',
httpMethod: 'GET',
...
pathParameters: { proxy: 'healthz' },
stageVariables: { alias: 'v1' },
...
}
In aws-serverless-express
code there is event
handling:
function getPathWithQueryStringParams (event) {
return url.format({ pathname: event.path, query: event.queryStringParameters })
}
that refers to event.path
, as it should, of course.
Of course, in the above case the following code would result in Lambda timeout, as there is no /custom/healthz
endpoint defined (if only accidentally).
(Non)Resolution
Based on a suggestion from AWS support, we should use event.pathParameters.proxy
instead of event.path
, which is consistent in all cases.
This is, of course, absolutely incorrect and constitutes a bug in AWS APIGW resolution mechanism that breaks the Lambda encapsulation. The /custom
path should have never been propagated beyond APIGW.
Suggestions and such
On a practical level, this issue means that we can't use custom base path mapping, as aws-serverless-express
doesn't provide any means (since the function in question is in closure and as such can't be overridden) to "hack" around this, without altering the Lambda's code.
It is also clear that AWS APIGE won't fix this any time soon or ever.
What can you guys suggest?