-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Support for key transform in JSON::Serializable::Options
#10793
Comments
This is a really good idea! |
I do wonder if this wouldn't be easier with just a symbol instead of a class. What would the method to convert the key look like? It seems like it would need to be a macro? But we don't have custom macro methods... Just thinking out loud. |
yet 😉. cough #8835 cough.
FWIW, Athena's serializer supports this via a symbol as well: either |
The transform should be able to happen at runtime, as this is when all the key matching runs too: crystal/src/json/serialization.cr Lines 192 to 195 in a190f24
Doing this also allows a little more flexibility in non std-lib usage of this as it can be extended arbitrarily to match all the |
Further thoughts on behaviour: if a |
As an alternative solution, we could use a method hook to transform the key value. By default, the method would just return the input value, but it can be overridden to apply any kind of transformations. struct Example
include JSON::Serializable
property an_example_key : Int32
property another_item : String
protected def convert_json_key(value)
value.camelcase
end
end |
@straight-shoota But then if you want to share this functionality you still end up with some kind of converter modules which you include. |
Yes, that's similar. But the benefit of this solution is that it's easier to implement a customized mapping. Simple upper or lower camelcase may work well in many use cases, but I'm pretty sure that quite often there's need for more control, because maybe just one or two field names have some inconsistencies not covered by the generic transformation. |
Since module already has Class annotation Interface could be something like def self.from_json_key(val)
def self.to_json_key(val) This will have the added benefits of:
|
I think two-way conversion would be unnecessary and could easily lead to inconsistencies when the transformations do not match up exactly. |
for me this struct Example
include JSON::Serializable
include JSON::Serializable::CamelCaseKey
property an_example_key : Int32
property another_item : String
end
module JSON::Serializable::CamelCaseKey
protected def convert_json_key(value)
value.camelcase
end
end |
but then one-way conversion is definitely going to lead to inconsistent output of to_json, as field name is already converted/transformed during the conversion and there is no memoization mechanism in place which can keep track of original value. |
Annotation syntax is hard to get used to and annotation usage in API is quite limited, so at first glance it gives such weird feelings to its users, but that doesn't make this language feature obsolete. |
One-way conversion goes from ivar name to JSON field name. The ivar name is explicit in code, so that's a given and there's no need to convert to that. This conversion directly enables |
This is where i'm trying to understand how one way conversion is going to enable bi-directional |
In case key = pull.read_object_key
{% for name, value in properties %}
when convert_json_key({{value[:key]}})
# ...
{% end %}
end |
Feature Request
When mapping from an external JSON model to an internal type it is possible to use the
JSON::Field
annotation'skey
property to define any differences in naming. This works well for single keys that require explicit overrides, but becomes quite verbose when the key format itself differs.As an example, an external service may present
Which may be desirable to capture as:
This could be specified more succinctly by defining a single key transform for the object.
Adding a property—
key_converter
—that enables a converter (similar to theJSON::Field
converter
property) appears to be a clean solution for this. This would point to a type that definesfrom_json_key(String) : String
andto_json_key(String) : String
Proposal is to add support for this option, along with the following set of converters (each mapping to/from snake_case_form as per the default crystal naming convention):
LowerCamelCaseConverter
an_example
→"anExample"
UpperCamelCaseConverter
an_example
→"AnExample"
CapitalizedSnakeCaseConverter
an_example
→"AN_EXAMPLE"
The text was updated successfully, but these errors were encountered: