-
-
Notifications
You must be signed in to change notification settings - Fork 23
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
Add support for omitempty
field tag to exclude empty values from queries and headers
#107
Conversation
…eries and headers
Build is failing due to rate limiting in CodeCov - will try a rebuild later. |
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 update!
README.md
Outdated
Page int `in:"query=page;default=1"` | ||
PerPage int `in:"query=per_page;default=20"` | ||
IsMember bool `in:"query=is_member"` | ||
Search *string `in:"query=search,omitempty"` |
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 query
directive is designed in the signautre as query(name1, name2, ...)
, here the omitempty
will be read as the second name used in the query parameters. I'm thinking:
- if we should define a separate
omitempty
directive for this, i.e.in:"query=search;header=x-api-keyword;omitempty"
? - shall we just use
patch.Field[T]
as the field type, since it was designed for indicating absent values, i.e.Search patch.Field[string]
, whenSearch.Valid == false
, it will be omitted from the final resource.
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.
Using patch.Field[T]
for the field type would not be ideal for us as this would complicate using our library for consumers, if this can be handled purely by the stuct tags then this would be ideal.
I have updated it to use a new omitempty
directive now. I do agree it is better.
I'm not sure on the implementation - as the new directive doesn't take any action by itself - but is used inside the existing directives - maybe this is ok, or maybe there is a better way?
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 totally agree. I hope patch.Field[T]
should be used only in rare cases.
core/formencoder.go
Outdated
|
||
type FormEncoder struct { | ||
Setter func(key string, value []string) // form value setter | ||
} | ||
|
||
func (e *FormEncoder) Execute(rtm *DirectiveRuntime) error { | ||
tag := rtm.Resolver.Field.Tag.Get("in") | ||
if rtm.Value.IsZero() && strings.Contains(tag, "omitempty") { |
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 test is error prone. Either check
rtm.Directive.Argv
foromitempty
defined in a directive, orrtm.Resolver.GetDirective
foromitempty
defined as a single directive
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.
Thank you! Have gone with option 2.
core/formencoder.go
Outdated
|
||
type FormEncoder struct { | ||
Setter func(key string, value []string) // form value setter | ||
} | ||
|
||
func (e *FormEncoder) Execute(rtm *DirectiveRuntime) error { | ||
if rtm.Value.IsZero() { | ||
for _, d := range rtm.Resolver.Directives { | ||
if d.Name == "omitempty" { |
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.
maybe we could use a constant here to link this back to the actual directive?
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 it's okay. But we can use API rtm.Resolver.GetDirective("omitempty")
here to simplify the code.
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! missed that.
// DirectiveOmitEmpty is used with the DirectiveQuery, DirectiveForm, and DirectiveHeader to indicate that the field | ||
// should be omitted when the value is empty. | ||
// It does not have any affect when used by itself | ||
type DirectiveOmitEmpty struct{} |
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.
In the json package, omitempty
is a tag that affects both json marshalling and unmarshalling. Since we have modified the encoding
behaviour of using omitempty
here, I would suggest upgrading decoding
as well to have the similar effects. Otherwise, it might bring up suprises for users who expect omitempty
to work in the decoding function. Have you ever considered how it should behave in decoding?
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 that omitempty
only affects Marshal
with json, and not Unmarshal
- as such I think it only makes sense to only modify encoding
and not decoding
.
Or maybe I'm missing something obvious!
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, you're right. The omitempty
tag only influences the marshalling process (i.e., converting a Go struct into JSON).
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #107 +/- ##
==========================================
- Coverage 90.78% 90.70% -0.08%
==========================================
Files 34 35 +1
Lines 1530 1539 +9
==========================================
+ Hits 1389 1396 +7
- Misses 97 99 +2
Partials 44 44
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Adds support for an
omitempty
tag.Main use case is for query parameters where we may not want have empty keys
i.e.
/pets?name_pointer=
By adding
omitempty
to the tag then this the key will not appear in the query stringi.e.
This will create
/pets
This has been added to the
formencoder
so that it will also remove empty headers.I have picked
omitempty
as I feel this will feel most natural for engineers as they are likely already used to this syntax with JSON.