-
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
feat(dao) ngx.null — allows patch requests to remove opt. conf. params #2700
Conversation
Tests? |
Yes, tests are missing, I just wanted first know (as I did this adhoc), if this makes any sense. If we agree that this is a good addition, I will add tests as well. |
8abbabc
to
8a4a3f2
Compare
@p0pr0ck5 I added a couple of tests. |
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.
Cool stuff! Un-setting fields via PUT
/PATCH
requests has been a long time flaw in this API...
Because of the legacy aspect of this part of the code base, and because of the associated tech-debt with it (many parts of the code rely on the schema validator to be working as it has been for the past ~2 years), I think we need to cover this with a few more tests, in order to make sure we don't break anything (that appears to be the case already) and are not introducing a broken behavior either. I left a few notes, but also a few comments of things we need to address I think, mainly related to tests:
- fix the uris unset unit test to make it more atomic and not rely on the result of the previous test
- add a test for
default
attribute andngx.null
- add a test for
default
attribute andngx.null
with sub-schemas - add a test for the custom
func
validator to be properly called withnil
and nott[column]
- a test for fields with the
required
attribute to error out when givenngx.null
in both partial and full updates
@@ -83,6 +83,9 @@ function _M.validate_entity(tbl, schema, options) | |||
|
|||
if not partial_update then | |||
for column, v in pairs(schema.fields) do | |||
if t[column] == ngx.null then | |||
t[column] = 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.
Note to self: so if we do a full update (PUT
), and we set a field with a "default" attribute to NULL
, we actually pull a new value from the configured "default" attribute (text or function). The behavior is fine (I think?), as most fields with a "default" values are so because they are not supposed to be empty. But it is still a somewhat unexpected behavior I think. Nothing else to add, just dropping a note here...
@@ -185,7 +195,7 @@ function _M.validate_entity(tbl, schema, options) | |||
end | |||
end | |||
|
|||
if t[column] and type(t[column]) == "table" then | |||
if t[column] and t[column] ~= ngx.null and type(t[column]) == "table" 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.
Since type(ngx.null) == "userdata"
, it seems we can stick to if t[column] and type(t[column]) == "table" then
here? Explicitness is good though. Maybe a comment saying ngx.null
will also get skipped?
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.
I'm fine with both. Do we want to leave room open for mocking ngx.null = {}
?
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.
I don't think so, ngx.null
should be ngx.null
and nothing else imho
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.
It doesn't hurt for such a bloated piece of code to stay explicit after all... Leaving this as-is :)
for column, v in pairs(schema.fields) do | ||
if not partial_update then | ||
if t[column] == ngx.null then | ||
t[column] = 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.
ditto: it seems the behavior we envision here is to treat fields set with NULL
during a PUT
as if they were initially created (run validation as if they were left blank, which means generates defaults and defaults for their sub-schema).
Could we have a couple of tests for this behavior?
- A test asserting that during a
full
update, fields set tongx.null
are reset to theirdefault
- A test asserting that during a
full
update, fields with a sub-schema are reset to theirdefault
You can create a fixture schema for this (the schema validation tests do it), in order to avoid depending on schemas from plugins or core entities :)
@@ -604,6 +634,20 @@ helpers.for_each_dao(function(kong_config) | |||
assert.falsy(err) | |||
assert.same(api_fixture, api) | |||
end) | |||
it("unset ngx.null fields", function() |
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.
Because the previous test unsets uris
already, we don't know if this test succeeds because of the newly introduced code or because the previous test is already passing. Could we rework the logic a bit here? A suggestion would be to introduce the following in the previous test:
it("unset nil fields", function()
finally(function()
-- re add the `uris` field
api_fixture.uris = "/mockbin"
assert(api:update(api_fixture, api_fixture, { full = true}))
end)
-- rest of the test
end)
it("unset ngx.null fields", function()
-- ...
end)
@@ -563,6 +563,31 @@ describe("Admin API " .. kong_config.database, function() | |||
assert.same(json, in_db) | |||
end | |||
end) | |||
it_content_types("removes optional field with ngx.null", function(content_type) | |||
return function() | |||
-- TODO: how should ngx.null work with application/www-form-urlencoded? |
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.
It is probably out of the scope of this PR, which is just to make the Admin API/DAO accept the JSON null
type (which of course does not exist in application/www-form-urlencoded
), so nothing to worry about imo :)
local ok, err, new_fields = v.func(t[column], t, column) | ||
local ok, err, new_fields | ||
if t[column] == ngx.null then | ||
ok, err, new_fields = v.func(nil, t, column) |
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.
I think this should be tested too
Thanks to this change, we can now remove fields (if permitted by the entity schema) by passing a JSON NULL (`ngx.null` or `cjson.null`) to said field. A field updated with NULL during a PATCH (partial update) will retain its `ngx.null` value after validation, and the DAO must infer this value to the correct NULL representation of its interface (CQL/SQL). During a PUT (full update), fields with a JSON NULL will be treated as if they were not specified (like create). No such behavior is available when sending `application/x-www-form-urlencoded` MIME type requests, this is only to support `cjson.null`/`ngx.null`. Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
8a4a3f2
to
0f0e432
Compare
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.
Added all of the required tests in an edit to your commit!
Summary
Better handling of JSON
null
in DAO layer and validations.Also allows usage of JSON
null
to remove optional parameters usingPATCH
request, e.g. with HTTPie: