jsonapi.rb
jsonapi.rb copied to clipboard
Case-aware deserialization support
json-api clients adhering to the 1.0 recommendations may be likely to use dasherized (e.g. password-confirmation) keys. json-api clients adhering to the 1.1 recommendations may be likely to use camelCase (e.g. passwordConfirmation) keys. The JSONAPI::Deserialization jsonapi_deserialize method does not seem to offer modification to key names. It would be handy if it could (optionally) underscore-ify (snake-case) these keys, (e.g. password_confirmation) to conform to Rails expectations.
@ballPointPenguin I could take a look, though I have little to no use-cases related to this. So if you or somebody else has more free time, I'll be happy to review and merge a PR.
Thanks for the request!
Yes I'm curious if anybody else cares about this. In my case, I can easily modify my web client to use under_score case when serializing attributes to send to the API. But I would want to expect that any backend implementation of the json-api spec would conform to either the 1.0 kebab-case or the 1.1 camelCase recommendation. If I get inspired I may make a PR for this.
So far we've had to add a few monkey patches to get dash-case into snake_case and how we have some js clients wanting to use 1.1 with camelCase. It would be good to take in includes and params that are converted to snake_case automatically.
We sprinkle in
deep_transform_keys{ |key| key.to_s.underscore }.to_s.split(',').map(&:strip).compact
2.6.5 :011 > { "foo-bar": "cat" }.deep_transform_keys{ |key| key.to_s.underscore }.to_s.split(',').map(&:strip).compact => ["{"foo_bar"=>"cat"}"] 2.6.5 :012 > { "fooBar": "cat" }.deep_transform_keys{ |key| key.to_s.underscore }.to_s.split(',').map(&:strip).compact => ["{"foo_bar"=>"cat"}"]
The serialiser already supports spitting things out in the format we expect and you can pass in a param so it knows to return camelCase or dash-case. Rails itself will forever be snake_case so we don't need to worry about that.
For rails 5 plus I found this little snippet that you can add to an initialiser instead of monkey patching the gem. The only issue comes where we are wanting to use the includes and filter keywords with non rails case.
# Transform JSON request param keys from JSON-conventional camelCase to
# Rails-conventional snake_case:
ActionDispatch::Request.parameter_parsers[:json] = -> (raw_post) {
# Modified from action_dispatch/http/parameters.rb
data = ActiveSupport::JSON.decode(raw_post)
data = {:_json => data} unless data.is_a?(Hash)
# Transform camelCase param keys to snake_case:
data.deep_transform_keys!(&:underscore)
}
I'd like to make it clear that the above can have unexpected effect on the serialized document. See the recent discussion regarding this exact issue: https://github.com/fast-jsonapi/fast_jsonapi/issues/62#issuecomment-590415588
If you still want to hook into the pre-deserialization, consider the parsers API in Rails, we leverage that and right now it's just aliasing the json parser:
https://github.com/stas/jsonapi.rb/blob/master/lib/jsonapi/rails.rb#L24-L28
Or alternatively, use the deserialization support we have and overwrite the (application) controller method.
:warning::warning::warning: Again, JSONAPI format doesn't apply the type transformation over the whole document, just to the spec-covered parts of it, so be careful with what you roll out into production.