jsonapi.rb icon indicating copy to clipboard operation
jsonapi.rb copied to clipboard

Replace `#as_json` with `#to_h` because of wrong object value parsing

Open relaxcore opened this issue 5 years ago • 9 comments

What is the current behavior?

The Deserialization module use as_json to represent input params as JSON. But it change all objects (uploaded files, rails models, etc) to strings. Same as use to_s on them.

Example:

params = { data: { attributes: { file: ::File.new(any_existing_filepath) } } }

params.as_json.deep_stringify_keys.dig('data', 'attributes', 'file').class # => String
params.to_h.deep_stringify_keys.dig('data', 'attributes', 'file').class # => File

What is the new behavior?

File attributes in deserialized data have the correct type

Checklist

Please make sure the following requirements are complete:

  • [x] Tests for the changes have been added (for bug fixes / features)
  • [x] Docs have been reviewed and added / updated if needed (for bug fixes / features)
  • [ ] All automated checks pass (CI/CD)

relaxcore avatar Jan 21 '21 11:01 relaxcore

@relaxcore this looks good, except for the part with with_indifferent_access (I'm trying to stay away from Rails stuff).

I imagine you're using the jsonapi_deserialize as part of a multipart request, please correct me if I'm wrong?!

Thank you!

stas avatar Jan 21 '21 16:01 stas

@stas you're right 😄 Just replaced #with_indifferent_access method with #deep_stringify_keys. Should be okay as well

relaxcore avatar Jan 21 '21 16:01 relaxcore

@relaxcore that's still ActiveSupport :honey_pot:

Let's just leave it without :)

stas avatar Jan 21 '21 16:01 stas

@stas it won't work in this way just after #to_h. As I understood, keys should be a strings, not symbols

{ data: {} }.as_json.keys.first.class # => String
{ data: {} }.to_h.keys.first.class # => Symbol

BTW, #as_json is also ActiveSupport 😸

relaxcore avatar Jan 21 '21 17:01 relaxcore

@relaxcore consider using #transform_keys(&:to_s): https://devdocs.io/ruby~3/hash#method-i-transform_keys

stas avatar Jan 21 '21 17:01 stas

@stas that's also not a good idea, cause it won't "stringify" nested keys, like attributes, etc. With current #as_json logic all nested keys are strings

relaxcore avatar Jan 21 '21 17:01 relaxcore

@relaxcore sorry for the delay. Before we look into technical solutions here, would you be kind to explain a bit what's the use-case here.

From my side it's hard to understand how you ended up deserializing a JSONAPI request with a file upload, since it usually requires an application/json content-type. Are you sending multipart requests and trying to stick to JSONAPI format?

stas avatar Jan 25 '21 21:01 stas

@stas Everything is pretty simple and as you said. Just have one multipart request and find such behavior

relaxcore avatar Jan 27 '21 09:01 relaxcore

@relaxcore sorry for the delay here.

Please let me know if you're still interested in wrapping this up. What I'd like to suggest here is to make the support for deep_stringify_keys pluggable, in a similar way it's done here: https://github.com/stas/jsonapi.rb/blob/master/lib/jsonapi/deserialization.rb#L1-L9

It looks like dry-transformer can be used here https://github.com/dry-rb/dry-transformer/blob/master/lib/dry/transformer/hash.rb

Please let me know what you think. Thanks again for sending the PR.

stas avatar Feb 14 '21 21:02 stas

Bump. Any updates on this?

alakra avatar Mar 08 '23 19:03 alakra