-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
enabling lambda functions to return custom status, body, and headers #3427
enabling lambda functions to return custom status, body, and headers #3427
Conversation
Any feedback on this? Or just waiting for the next release? |
Hey guys! Any chance on this making the next release? |
Thanks for the sweet contribution! Works for me on my now super-patched Kong Lambda plugin. Python syntax of the above: return {
'statusCode': 201,
'body': {
'key1': 'some_value_post1',
'key2': 'some_value_post2',
'key3': 'some_value_post3'
},
'headers': {
'X-Custom-Header': 'Hello world!'
}
} |
AWS plugin throws an error if the lambda doesn't return a response body |
hey @thibaultcha this one missed the last release. I've rebased it, so I'd love some feedback and to get this merged in! @Curistofa it should no longer throw any errors if Lambda doesn't return a body. |
FYI: I'm designing this to be in line with the AWS API Gateway functionality. For a custom response to work with API Gateway, the requirements are that the function must return a JSON object that looks like:
|
Not sure why the tests are failing. All the tests for the lambda plugin pass, but it looks like a test with the udp plugin failed as well as some cassandra ring health checks. Do those sometimes spontaneously fail @thibaultcha @bungle ? |
Some tests eventually fail yes, that happens. Btw, I am away for a couple of weeks. But @bungle can help you.
… On Jul 11, 2018, at 6:32 PM, Alois ***@***.***> wrote:
Not sure why the tests are failing. All the tests for the lambda plugin pass, but it looks like a test with the udp plugin failed as well as some cassandra ring health checks. Do those sometimes spontaneously fail @thibaultcha @bungle ?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
|
@bungle any feedback on this? |
any thoughts? |
Nice job! That's exactly what I was looking for. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be quite the popular PR, let's give it some more attention! As such, here is my first round of review :)
Thank you @aloisbarreras for the patch!
kong/plugins/aws-lambda/handler.lua
Outdated
-- this will return the custom response object, otherwise nil | ||
local function extract_custom_response(content) | ||
local serialized_content = cjson.decode(content) | ||
if (not serialized_content) then return nil end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will you please remove parenthesis from the conditions in this patch? The same way, please avoid 1 liner branches like this one, and prefer:
if thing then
return
end
Both of these guidelines are detailed in our CONTRIBUTING.md file. Thanks.
kong/plugins/aws-lambda/handler.lua
Outdated
local headers = serialized_content.headers or {} | ||
local body | ||
if (serialized_content.body ~= nil) | ||
then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: please keep the then
on the previous line as well, since the line is short enough.
kong/plugins/aws-lambda/handler.lua
Outdated
local function extract_custom_response(content) | ||
local serialized_content = cjson.decode(content) | ||
if (not serialized_content) then return nil end | ||
local statusCode = tonumber(serialized_content.statusCode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: please prefer snake_case over camelCase for variable names - this rule is also detailed in our codestyle and enforced throughout the codebase. Of course, the serialized_content.statusCode
one is fine.
Thanks!
kong/plugins/aws-lambda/handler.lua
Outdated
} | ||
end | ||
|
||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove this instruction which is redundant since the function will return nil
anyway by default.
kong/plugins/aws-lambda/handler.lua
Outdated
@@ -186,6 +215,12 @@ function AWSLambdaHandler:access(conf) | |||
return responses.send_HTTP_INTERNAL_SERVER_ERROR(err) | |||
end | |||
|
|||
local customResponse = extract_custom_response(content) | |||
if (customResponse) then | |||
local mergedHeaders = utils.table_merge(headers, customResponse.headers) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: ditto, please avoid camel case variable names here and above (L.218).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tests: in case of a duplicated header (found in both headers
and customResponse.headers
), headers from the latter will override headers from the former (due to the underlying implementation of utils.table_merge()
. We should probably provide a test for this behavior.
kong/plugins/aws-lambda/handler.lua
Outdated
local customResponse = extract_custom_response(content) | ||
if (customResponse) then | ||
local mergedHeaders = utils.table_merge(headers, customResponse.headers) | ||
return send(customResponse.status_code, customResponse.body, mergedHeaders) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We cannot directly call send
from this plugin (see #3079). Please follow the below pattern L.234 to 245, and set the proper ctx.delayed_response
and ctx.delayed_response_callback
. Ideally, we should not duplicate this code.
assert.res_status(201, res) | ||
assert.equal(0, tonumber(res.headers["Content-Length"])) | ||
assert.equal(nil, res.headers["X-Custom-Header"]) | ||
assert.equal(res:read_body(), "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The order of arguments is wrong here, it should be: (expected, found)
. Also, the above assert.res_status()
call already returns the body, this can be rewritten as:
local body = assert.res_status(201, res)
-- ...
assert.equal("", body)
Ditto in the previous test - thanks!
kong/plugins/aws-lambda/handler.lua
Outdated
if (not serialized_content) then return nil end | ||
local statusCode = tonumber(serialized_content.statusCode) | ||
|
||
if (statusCode) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tests: there seems to be no test that ensures that if a body
is given, but no statusCode
, then the Lambda's response has no effect on the proxy's response.
Just to make sure, is this the behavior followed by the AWS API Gateway? Great if it is! If not, then we should probably implement the same.
@aloisbarreras We would also ask of you (or anyone else willing to contribute them) that you provide documentation for this change, in the https://github.com/Kong/docs.konghq.com repository - thank you! |
Okay @thibaultcha I've addressed your feedback, and I think everything looks good. However, I was just reading more about how AWS API Gateway works with Lambda and I didn't realize that you have to pick That begs the question, should I add an option to the plugin configuration that enables this? I'd love some feedback from you and other community members on what they would like to see. If we do go with that option, then the required format of the Lambda response is described here. There's an |
@aloisbarreras Thanks for verifying. I do feel like this should be an option considering the opinionated behaviour of the plugin on such responses, but I never used it myself. Yes, we should gather feedback from the rest of the community here. Considering the attention this PR has received so far, it shouldn't be too hard to gather a few opinions I hope :) Please chime in if you are waiting for this PR! |
Okay here is my updated proposal: Add an I'm modeling the structure after the existing API Gateway functionality, which is this: With the Lambda proxy integration, API Gateway requires the backend Lambda function to return output according to the following JSON format:
In the output, headers can be unspecified if no extra response headers are to be returned. ... The output body is marshalled to the frontend as the method response payload. If body is a binary blob, you can encode it as a Base64-encoded string and set isBase64Encoded to true. Otherwise, you can set it to false or leave it unspecified. If the function output is of a different format, API Gateway returns a 502 Bad Gateway error response. The My only hang up now is that I've never used the Once we think this looks good, I'll update the docs for the plugin as well. |
kong/plugins/aws-lambda/handler.lua
Outdated
@@ -9,6 +9,8 @@ local meta = require "kong.meta" | |||
local http = require "resty.http" | |||
local cjson = require "cjson.safe" | |||
local public_utils = require "kong.tools.public" | |||
local aws_lambda_proxy_schema = require "kong.plugins.aws-lambda.proxy_response_schema" | |||
local schemas = require "kong.dao.schemas_validation" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please do not use this module, as it is deprecated in favour of the new schema module written for the new DAO.
Overall, I question the dependency on either schema modules to perform such validations in this plugin (or any other plugin). The schemas (and their validation functions) are not meant for public consumption since there is no guarantee that their API or behaviour won't break in the future. They are meant to declaratively specify DAO entities only, and I fear that using them in plugins breaks the single responsibility principle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay I'll change that up. It just seemed like the easiest way to do some validation.
Have any recommendations for how to validate the response format? I can roll my own function with some type() checks and if statements if that works. I have a Node background, so normally there's an npm package for everything 😄 . I'm not sure if there's a convention in Lua that I should follow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job !
According to Lambda proxy integration, the body is not specified to be optionnal. However headers is clearly specified to be optionnal. I'm working on the documentation for this PR |
@aloisbarreras Hey there, just a nudge: will you be able to address the review comments? |
hey @thibaultcha . Yes! Sorry work has been crazy. I will finish this by EOW. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates @aloisbarreras! I believe that we are almost there :)
On the base64 encoding point:
I've never used the isBase64Encoded option with API Gateway, so I don't know what the use case for that is.
I believe that is answered by the documentation you quoted:
If body is a binary blob, you can encode it as a Base64-encoded string and set isBase64Encoded to true
I do not believe implementing this option in this PR is a requirement, but I wonder how many of the folks who requested this PR would need it. And if so, we'd welcome a subsequent contribution once this gets merged.
Thank you!
@@ -59,6 +59,7 @@ local _M = { | |||
HTTP_CONFLICT = 409, | |||
HTTP_UNSUPPORTED_MEDIA_TYPE = 415, | |||
HTTP_INTERNAL_SERVER_ERROR = 500, | |||
HTTP_BAD_GATEWAY = 502, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change warrants that we modify this logic, otherwise, we'd be sending underlying error messages to the client that really are internal error logs. (Talking about the above call in if not proxy_response then
. Thoughts? Of course, such a change deserves the appropriate test cases to be added in responses_spec.lua
(see https://github.com/Kong/kong/blob/fc15f586006c612edd8ce75e0f6b11ab9f864723/spec/01-unit/009-responses_spec.lua#L62).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that makes sense. I updated the logic and test, let me know if you have any other feedback.
ngx response values A Lambda function can now return an object that sets a custom http status, body, and headers on the ngx response to the client. Previously, Kong would return a 200 or 202 no matter what the Lambda function responded with. This new behavior brings Kong to parity with AWS API Gateway and will make migrating from that platform much easier.
add new response type and updating test to ensure that ngx.log is called to log the internal error
Add a new response type and update the tests to ensure that ngx.log is called to log the internal error. From #3427 Signed-off-by: Thibault Charbonnier <[email protected]>
Summary ------- Previously, Kong would return a 200 or 202 no matter what the Lambda function responded with. Now, a Lambda function can now return an object that sets a custom HTTP status code, headers, and body. Kong will use these values to override the response sent back to the client. This new behavior brings Kong to parity with AWS API Gateway and will make migrating from that platform much easier. Read more on Lambda Proxy Integration here: https://docs.aws.amazon.com/apigateway/latest/developerguide/getting-started-with-lambda-integration.html The supported response format from the Lamda is: { "statusCode": 201, "headers": { "headerName": "headerValue", ... }, "body": "..." } Changes ------- * Add `is_proxy_integration` option to schema (disabled by default). When enabled, the behavior described above will be in effect. * Invalid response formats will result in a 502 response from Kong. * Add test cases for returning a custom response from Lambda. NYI --- Not yet implemented: * Support for `isBase64Encoded` See --- From #3427 Signed-off-by: Thibault Charbonnier <[email protected]>
Merged to master! Thank you for your hard work on this @aloisbarreras! 🎉 👍 I made a few tweaks locally, added a few test cases, extended the commit message, and did some cleanup/squashing. Kong 1.0 rc2 will ship with this new Lambda Proxy Integration (between now and the next couple of weeks). Thanks to everybody who helped and to those who expressed their interest in this as well (by emojis or even in person). The docs PR opened by @romdsj can be seen here, and will be published when Kong 1.0 is released. We will be refining it, and until then, the PR can be used as documentation for this yet to be released feature :) On the "NYI" (not yet implemented) list for this feature, I noted the lack of support for |
Feature from Kong/kong#3427 but backported to support Kong 0.13.1 NOTE: does not include test fixtures, see code comments
Feature from Kong/kong#3427 but backported to support Kong 0.13.1 NOTE: does not include test fixtures, see code comments
Feature from Kong/kong#3427 but backported to support Kong 0.13.1 NOTE: does not include test fixtures, see code comments
Feature from Kong/kong#3427 but backported to support Kong 0.13.1 NOTE: does not include test fixtures, see code comments
Feature from #3427 but backported to support Kong 0.13.1 NOTE: does not include test fixtures, see code comments
NOTE: Please read the CONTRIBUTING.md guidelines before submitting your patch,
and ensure you followed them all:
https://github.com/Kong/kong/blob/master/CONTRIBUTING.md#contributing
Summary
Currently, the AWS Lambda plugin will only return a 200, 202, or 204 HTTP status response code on successful requests. This adds the ability for Lambda functions to define custom response status codes by returning a specific object. For example returning the following from a Lambda function will set custom values on the Kong response.
Returning this from your Lambda function would set that status to 201, the response body to
body
and add the custom headers inheaders
.This same functionality is already present with API Gateway, and it would be great to replicate it here. It would make switching from API Gateway to Kong seamless :).
Full changelog