-
Notifications
You must be signed in to change notification settings - Fork 77
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
WIP: Allow :only and :except when enabling underscore_to_dash #137
Conversation
@wasnotrice Great work! I really like the test apparatus improvements here as well. 👍 I have a proposal if you agree. First PR would be the regex modification (that we could get in quickly). Part 2 would be the rest of this PR. Let me know if you think that is feasible (I understand if no as it might be a bit hard to separate out). |
@snewcomer thanks for the review. I could definitely break out the regex modification (that's really just changing the regex). I'll do that and then rebase this PR once it's merged. I realize there are a few different things happening in this PR—I tried to highlight them in the initial comment. Maybe it would be easier to review if I also broke out the improvements to test apparatus for existing tests? Plus I see that the formatter failed. Boo :) |
0acc52d
to
27867a9
Compare
27867a9
to
436f508
Compare
Not sure why the formatter is failing in CI—it passes on 1.7.3 |
This has been rebased on master. I removed the additional |
assert attributes["metadata"] == data[:metadata] | ||
assert attributes["_private_attribute"] == data[:_private_attribute] | ||
|
||
assert Enum.find(included, fn i -> i[:type] == "user" && i[:id] == "2" end)[:attributes][ |
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 personally find these assert
statements very difficult to grok, can we clean them up in any way? It may be possible to use a pipeline:
assert "bonds" == included
|> Enum.find(&(&1.type == "user" && &1.id == "2")
|> get_in([:attributes, "last-name"])
# Or perhaps with a capture
last_name = included
|> Enum.find(&(&1.type == "user" && &1.id == "2")
|> get_in([:attributes, "last-name"])
assert "bonds" == last_name
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 agree! These are modeled after other tests in this file (see line 441). I thought it would be better to keep same style while adding tests, to focus on the content of this addition.
Another option would be to add some helper functions to the tests:
assert "bonds" ==
included
|> find_user_with_id("2")
|> get_attribute("last-name")
Do you want to address this here, or would it be better to do a separate PR to improve readability of these 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.
Agree with the pipeline style for these tests. And I would imagine another PR would be preferable.
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.
@wasnotrice I really like this PR. And thanks again for getting in the regex work. 👍
@@ -93,6 +95,8 @@ defmodule JSONAPI.QueryParserTest do | |||
config = struct(Config, view: MyView) | |||
assert parse_include(config, "author.top-posts").includes == [author: :top_posts] | |||
assert parse_include(config, "best-friends").includes == [:best_friends] | |||
assert parse_include(config, "_private-friend").includes == [:_private_friend] | |||
assert parse_include(config, "nonstandard__friend").includes == [:nonstandard__friend] |
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.
👍
:full_description, | ||
:inserted_at, | ||
:metadata, | ||
:_private_attribute, |
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.
What are your thoughts on including these keys in the original Post
view and testing that? Got lots of views in there ;)
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 reason I created a new view was so that the "basic" tests could keep using the simpler view, and I wanted to make as small of an impact on existing tests as I could. But I agree, this view duplicates a lot. I'd be happy to merge them if that's preferred
assert attributes["metadata"] == data[:metadata] | ||
assert attributes["_private_attribute"] == data[:_private_attribute] | ||
|
||
assert Enum.find(included, fn i -> i[:type] == "user" && i[:id] == "2" end)[:attributes][ |
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.
Agree with the pipeline style for these tests. And I would imagine another PR would be preferable.
lib/jsonapi/utils/underscore.ex
Outdated
@@ -3,7 +3,7 @@ defmodule JSONAPI.Utils.Underscore do | |||
Helpers for replacing underscores with dashes. | |||
""" | |||
|
|||
def underscore?, do: Application.get_env(:jsonapi, :underscore_to_dash, false) | |||
def underscore?, do: Application.get_env(:jsonapi, :underscore_to_dash, false) != false |
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.
Should we make the config a module attribute above and use it here and down in the underscore?/1
?
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.
Sure—good idea
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.
Well, I guess not—the module attribute doesn't work for our tests, since we change the config at runtime—I made the config into a function instead
{underscore(key), underscore(value)} | ||
else | ||
{underscore(key), value} | ||
end | ||
end | ||
|
||
defp underscore?(key) do | ||
config_specifies_underscore?(config(), key) |
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.
could we unwrap this and use config_specifies_underscore?
directly?
Lots of really nice work here Eric! One question that I thought I should at least ask, while hopefully not discounting the great work you did - Do we want this configuration here? The only reason I thought I would ask is the original issue pointed out a missing gap with keys with double underscores and what not. That was fixed in #139. Essentially wondering - what the strong motivation for this? More or less simply curious as I don't have a need but I'm sure others here do. 👍 |
@snewcomer there is more to the original issue. The original issue was that my API allows a user to store arbitrary JSON. But when they retrieve the JSON they stored, it get processed by So, the strong motivation for this is to allow people to control the format of their jsonapi keys (underscore/dash) while also allowing them to designate content whose format should not be changed, regardless of the format of the response keys. To that end, I think the most effective place for this is not actually in the application env, but instead per-view. I think that's totally doable, and if folks agree, I could build that out either here, or in a followup PR. I opened this PR in order to provide a more concrete way to discuss the feature, so discussing it here is totally appropriate! Although I guess it would make more sense to focus first on this sort of high-level question of appropriateness/desirability before we get deep into implementation details :) |
@@ -42,9 +42,13 @@ defmodule JSONAPI.Utils.Underscore do | |||
"_top__posts_" | |||
""" | |||
def underscore(value) when is_atom(value) do |
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.
These method names seem confusing to me :). Really it is dasherize
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.
:) yes I agree, they would make more sense to me if switched
I think generally I am hoping to get some more broad thoughts on how From my understanding, JSONAPI defines strong conventions for how the
https://jsonapi.org/format/#document-member-names So my question is, what level of "strictness" should we apply? If we followed the spec, then There are escape hatches such as All of this is simply discussion points and not meant to discredit any ideas here. Would love to hear some more thoughts from more ppl! |
Sorry @snewcomer I hadn't seen your comments here. This is a very valid discussion and I want to mull this over a bit before making a decision. I'd love to get @jeregrine's thoughts as well 😁 |
@wasnotrice I was wondering if you're still interested in submitting this PR. We'd love to include it in a future release. |
@jherdman absolutely—I'd love to get it in when we decide how it fits into the project! |
Fix for #132
This adds the option to specify
or
For serialization the tests are pretty solid. I haven't built out the various edge case tests for query parsing yet. Thought I'd get some feedback first.
Notes:
I modified the
underscore
functions to accept a view, but the view is just ignored right now. I was thinking it would be nice to be able to specify keys per-view. I couldn't come up with a great way to configure that, so that view just gets passed along, and doesn't do anything yet. But it's ready and waiting. One option would be to allow for{ViewModule, :special_key}
tuples in the Application.env lists. Any thought on this?The current behavior is that when the config specifies keys, both the key and its value gets the same treatment. So if a key is in the
only
list, then it and its value are run through theunderscore
function. If not, neither the key nor the value are. Similarly for theexcept
list.I haven't done any testing for the scenario where a user might specify both
only
andexcept
, but ifonly
is present, it will win, and except will be ignored.I added some
describe
blocks around the tests that modifyApplication.env
, so that we can unset the changes in an on_exit block. This makes the tests more reliable when there are failures (i.e. the Application.env doesn't leak into other tests)