Skip to content
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

Merged
merged 1 commit into from
Jul 25, 2017

Conversation

bungle
Copy link
Member

@bungle bungle commented Jul 13, 2017

Summary

Better handling of JSON null in DAO layer and validations.

Also allows usage of JSON null to remove optional parameters using PATCH request, e.g. with HTTPie:

http patch :8001/apis/test hosts:=null uris:=null

@p0pr0ck5
Copy link
Contributor

Tests?

@bungle
Copy link
Member Author

bungle commented Jul 14, 2017

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.

@bungle bungle added pr/changes requested Changes were requested to this PR by a maintainer. Please address them and ping back once done. and removed pr/status/please review labels Jul 14, 2017
@bungle bungle force-pushed the feat/dao-patch-null branch from 8abbabc to 8a4a3f2 Compare July 17, 2017 14:26
@bungle
Copy link
Member Author

bungle commented Jul 17, 2017

@p0pr0ck5 I added a couple of tests.

@bungle bungle added pr/status/please review and removed pr/changes requested Changes were requested to this PR by a maintainer. Please address them and ping back once done. labels Jul 17, 2017
Copy link
Member

@thibaultcha thibaultcha left a 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 and ngx.null
  • add a test for default attribute and ngx.null with sub-schemas
  • add a test for the custom func validator to be properly called with nil and not t[column]
  • a test for fields with the required attribute to error out when given ngx.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
Copy link
Member

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
Copy link
Member

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?

Copy link
Member Author

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 = {}?

Copy link
Member

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

Copy link
Member

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
Copy link
Member

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 to ngx.null are reset to their default
  • A test asserting that during a full update, fields with a sub-schema are reset to their default

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()
Copy link
Member

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?
Copy link
Member

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)
Copy link
Member

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

@thibaultcha thibaultcha added pr/changes requested Changes were requested to this PR by a maintainer. Please address them and ping back once done. and removed pr/status/please review labels Jul 22, 2017
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>
@thibaultcha thibaultcha force-pushed the feat/dao-patch-null branch from 8a4a3f2 to 0f0e432 Compare July 25, 2017 21:24
Copy link
Member

@thibaultcha thibaultcha left a 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!

@thibaultcha thibaultcha merged commit fc82dd7 into next Jul 25, 2017
@thibaultcha thibaultcha deleted the feat/dao-patch-null branch July 25, 2017 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr/changes requested Changes were requested to this PR by a maintainer. Please address them and ping back once done.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants