-
Notifications
You must be signed in to change notification settings - Fork 88
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 JSON::Serializable #253
Support JSON::Serializable #253
Conversation
Latest commit adds support for the Usage is like Is it worth adding specs for each of these options, or at this point are we just testing the std lib? |
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.
@Blacksmoke16 This looks so much better. Thanks! 💯
👍 Yea no kidding, much better. Don't merge yet, think i want to include some more details in readme on at least the |
@Blacksmoke16 Is there any side affects using the native version? I recall attempting this before but the constructor required supporting the JSON::Puller or something like that. |
This is a bit difference than the JSON.mapping version. This was just released with Crystal 0.25.0. Using this it isn't possible to give like All the tests passed and all the Serializable extra stuff seems to work fine so unless something comes up i think we're good. |
aaah, I was wondering how this was possible without the constructor. I will checkout 0.25 release notes for more info. This is all excellent news! I prefer the |
https://crystal-lang.org/api/0.25.1/JSON/Serializable.html Is a good overview of it. |
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 love how much this simplifies the code.
The only danger sign I see is the dependence on JSON::Serializable's use of after_initialize
, which is apparently undocumented.
The annotations feel like a hack, but that's not your doing, it's just the way the stdlib was implemented.
I have a hunch json::serializable is going to get a substantial refactor before it really solidifies in crystal. We'll see I guess.
src/granite/error.cr
Outdated
else | ||
"#{@field.to_s.capitalize} #{message}" | ||
end | ||
(@field == :base) ? @message : "#{@field.to_s.capitalize} #{message}" |
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.
Can we leave this as it was? I don't see the benefit to the more subtle syntax.
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 can change it back if you want. I just have a thing for ternary, easier to read and cleaner imo.
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 guess this is the sort of thing that a style guide helps communicate. My preference is to avoid ternaries wherever possible.
More than anything, this is an unrelated change to the rest of the pull. I don’t feel really strong about changing this, but I’d like to avoid someone else changing it back simply because they prefer it to be the other way. It just creates more potential for bugs to sneak in and opens the door for endless bike shedding.
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.
Fair enough.
@@ -39,6 +39,9 @@ module Granite::Fields | |||
{% for name, options in FIELDS %} | |||
{% type = options[:type] %} | |||
{% suffixes = options[:raise_on_nil] ? ["?", ""] : ["", "!"] %} | |||
{% if options[:json_options] %} | |||
@[JSON::Field({{**options[:json_options]}})] | |||
{% 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.
clever, I like it.
There is no dependence on It could be removed and the basic implementation would still be fine. It is just a method that gets called after the |
Updated README on JSON support. Can see it at https://github.com/Blacksmoke16/granite/tree/JSON-Serializable-support#json-support. Otherwise this is good to merge unless one of you finds an issue. |
@robacarp can we merge this? |
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 @Blacksmoke16
This PR, fixes #253 brings about native support for JSON::Serializable. This is super exciting and probably my favorite PR so far. The benefits of this are immense, especially when working with JSON APIs.
Single Object
foo = Foo.from_json(%({"name": "Granite", "age": 10}))
foo.to_json
Array of Objects
foo = Array(Foo).from_json(%([{"name": "Granite1", "age": 10},{"name": "Granite2", "age": 50}]))
foo.to_json
It works pretty much out of the box, but with one slight breaking change. By default, as you may have noticed above, when doing
to_json
it will not add nil values into the object, i.e. theid
. If the user wants that, they would have to do:foo = Foo.from_json(%({"name": "Granite", "age": 10}))
foo.to_json
after_initialize
Another cool feature this brings is the
after_initialize
method. This method gets called afterfrom_json
is done parsing the given json. This allows you to set other fields that are not in the JSON directly or that require some more logic.foo = Foo.from_json(%({"name": "Granite1"}))
JSON::Serializable::Unmapped
foo = Foo.from_json(%({"name": "Granite1", "age": 12, "foobar": true}))
foo.to_json
on_to_json
Allows the user to tap into the
to_json
and do additional manipulations before returning it.foo = Foo.from_json(%({"name": "Granite1", "age": 12}))
foo.to_json