Skip to content

[WIP] Initial Implementation #1

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

Closed
wants to merge 2 commits into from
Closed

Conversation

NullVoxPopuli
Copy link
Collaborator

Just working out thoughts in here, trying to figure out API, etc.

@beauby
Copy link
Owner

beauby commented Oct 19, 2016

Looks like a promising start 👍. I'll post some API suggestions here later.

@beauby
Copy link
Owner

beauby commented Oct 19, 2016

So what I had in mind was:

  • anonymous/default deserialization
hash = JSONAPI::Rails::DeserializableResource[Post].(document)
  • customized
class DeserializableCreatePost < JSONAPI::Rails::DeserializableResource[Post]
  attribute :foo, required: true
  attribute :bar
  has_many :baz, types: ['foo', 'bar']
  has_one :foobar, required: true
end

hash = DeserializableCreatePost.(params)

@NullVoxPopuli
Copy link
Collaborator Author

NullVoxPopuli commented Oct 19, 2016

JSONAPI::Rails::DeserializableResource[Post].(document)

I like this, it's the same/similar pattern as the ralis 5 migrations.

for the customized one, I like how that idea could be used in place of strong parameters -- and probably would allow for easier extension if people wanted to get funky with their JSON API create/update requests

Also, how do you feel about caching the result of JSONAPI::Rails::DeserializableResource[klass]?

Thanks!

@beauby
Copy link
Owner

beauby commented Oct 19, 2016

Re. caching: sure, but that's easy once everything is in place.
Also, possible alternative DSL:

class DeserializableCreatePost < JSONAPI::Rails::DeserializableResource[Post]
  required do
    attribute :foo
    has_one :foobar
  end
  optional do
    attribute :bar
    has_many :baz, types: ['foo', 'bar']
  end
end

@NullVoxPopuli
Copy link
Collaborator Author

NullVoxPopuli commented Oct 19, 2016

I like that alternative DSL, as it more closely matches DeserializableResource from jsonapi/deserializable.

Ultimately, it's going to be a subclass either way, so the DSL can go either way (just whatever jsonapi/deserializable allows)

@beauby
Copy link
Owner

beauby commented Oct 19, 2016

Yeah, plus it gives a clearer view.

@beauby
Copy link
Owner

beauby commented Oct 19, 2016

I'm also pondering the benefits of having jsonapi-validations/jsonapi-deserializable be whitelist only, and delegate the actual presence (+format) validations (+type coercions) to something like dry-validation.

@NullVoxPopuli
Copy link
Collaborator Author

I'm all for simplification of implementation -- it allows for easier native extensions later. :-)

@beauby
Copy link
Owner

beauby commented Oct 19, 2016

So the journey of an incoming payload is:

  1. ensure the document is valid (jsonapi-parser)
  2. build hash from payload (jsonapi-deserializable) – as validation would not be done upfront, there could be failures there, that have to be handled in a smart way
  3. validate obtained hash (dry-validation)

and jsonapi-rails would provide a DSL to seamlessly do at least 1 and 2.

@NullVoxPopuli
Copy link
Collaborator Author

Yeah for the most part -- I'd said jsonapi-rails would be a drop in replacement for just step 2 -- to keep responsibility separated and such.

@beauby
Copy link
Owner

beauby commented Oct 21, 2016

Quick update here: I rewrote jsonapi-deserializable so that

  1. no more optional/required – it does whitelisting only (thus the dependency on jsonapi-validations is gone),
  2. it is built upon the principle of "if field foo is present, then add following members to the result hash" (this prevents one from building members from various attributes, but that's mainly useless anyways).

Hence, the DSL here could be as simple as:

DeserializablePost = JSONAPI::Rails::DeserializableResource[Post]
DeserializablePost.(params)
# => { ... }

which would easily be implemented as a front-end for jsonapi-deserializable.

@NullVoxPopuli
Copy link
Collaborator Author

excellent. I looked over your changes, and it does look really easy. I'll make some updates tomorrow morning!

@@ -0,0 +1,15 @@
module JSONAPI
require_relative 'jsonapi/rails'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why require_relative and not require?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was using require_relative everywhere else

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does not really address the question :D

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to require the whole path jsonapi/etc for every require.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but here this is the whole path. Plus it's not like we require shittons of stuff so I'd be in favor of using require everywhere.

@NullVoxPopuli
Copy link
Collaborator Author

I think this is getting to a good spot. I had to re-implement some old deserialization to make AMS's existing tests happy. But I'm not sure there is ever going to be a real world use case for the AMS testing scenarios. (where no Model object exists)

end
end

attr_accessor :_hash, :_options, :_klass
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why accessors?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

habit, they'd be fine as attr_readers, as they are never written to outside of instantiation.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But are they needed? Why not use instance variables?

@beauby
Copy link
Owner

beauby commented Oct 23, 2016

Some suggestions:

  1. Rename DeserialiazableResource to DeserializableModel (also, it may make sense to change the namespacing from JSONAPI::Rails::DeserializableModel to JSONAPI::Deserializable::Rails::Model – to be discussed)
  2. Get rid of the "unrestricted" thing. If you have no clue what you expect as incoming data, you have deeper issues than a missing deserialization layer.

@beauby
Copy link
Owner

beauby commented Oct 23, 2016

Also, we need to find a way to infer the attributes/relationships only if the user does not choose to define them themselves.

@beauby
Copy link
Owner

beauby commented Oct 23, 2016

The best answer to the problem mentioned above seems to be no runtime inference, but using generators instead.

@beauby
Copy link
Owner

beauby commented Oct 23, 2016

$ rails generate deserializable create_user user

# app/deserializables/create_user.rb
class DeserializableCreateUser < JSONAPI::Rails::DeserializableModel
  type
  id
  attribute :foo
  attribute :bar
  has_one :foobar
  has_many :barfoo
end

@beauby
Copy link
Owner

beauby commented Oct 23, 2016

After some more thoughts, renaming JSONAPI::Rails::DeserializableResource to JSONAPI::Deserializable::ActiveRecord seems to make sense. Let's discuss this when you're around @NullVoxPopuli.

@beauby
Copy link
Owner

beauby commented Oct 23, 2016

Regarding the generators, I implemented them in #2.

@NullVoxPopuli
Copy link
Collaborator Author

NullVoxPopuli commented Oct 23, 2016

  1. Rename DeserialiazableResource to DeserializableModel (also, it may make sense to change the namespacing from JSONAPI::Rails::DeserializableModel to JSONAPI::Deserializable::Rails::Model – to be discussed)

After some more thoughts, renaming JSONAPI::Rails::DeserializableResource to JSONAPI::Deserializable::ActiveRecord seems to make sense. Let's discuss this when you're around

I think I like JSONAPI::Deserializable::ActiveRecord the best :-)

  1. Get rid of the "unrestricted" thing. If you have no clue what you expect as incoming data, you have deeper issues than a missing deserialization layer.

Unrestricted is entirely for AMS -- which if we want to take deserialization testing out of AMS, then it's problem solved (which I would be in huge favor of).

Also, we need to find a way to infer the attributes/relationships only if the user does not choose to define them themselves.

I don't think this would be a problem, because the inferred attributes / relationships only take precedence if a deserializable isn't explicitly used (which would xe explicitly defined entirely, and not have inferred anything)

Regarding the generators, I implemented them in #2.

Nice work! I'll need to give it a test drive

@beauby
Copy link
Owner

beauby commented Oct 23, 2016

I don't think this would be a problem, because the inferred attributes / relationships only take precedence if a deserializable isn't explicitly used (which would xe explicitly defined entirely, and not have inferred anything)

It is, because if you decide not to allow those attributes anymore, you're toast.

@beauby
Copy link
Owner

beauby commented Oct 23, 2016

Regarding AMS and "unrestricted deserialization", I believe it is not an issue to get rid of it as deserialization has always been marked experimental in AMS.

@NullVoxPopuli
Copy link
Collaborator Author

It is, because if you decide not to allow those attributes anymore, you're toast.

how do you mean?

Regarding AMS and "unrestricted deserialization", I believe it is not an issue to get rid of it as deserialization has always been marked experimental in AMS.

excellent

@beauby
Copy link
Owner

beauby commented Oct 23, 2016

I mean, if you infer an attribute :foo, then you cannot get rid of it (:foo will always be whitelisted for that deserializable, no matter what DSL method you call).

@NullVoxPopuli
Copy link
Collaborator Author

right, I was just saying that to solve the problem, one could inherit from

JSONAPI::Deserializable::Resource and build the deserialization however they want

minor organization updates, spec planning

add some tests

minor test cleanup

add more tests

more testing, some cleanup - having AR class caching issues with relationsihps

it just returns nil :-/

remove puts

railsy result

add unrestricted deserializer for backward compatibility

remove unrestricted, and rename to JSONAPI::Deserializable::ActiveRecord

remove unrestricted, and rename to JSONAPI::Deserializable::ActiveRecord

looks like I forgot to add

add polymorphic check

remove unneeded attr_ settings

Add generators for (de)serializable models. (#2)

Revert "Add generators for (de)serializable models." (#7)
@NullVoxPopuli NullVoxPopuli force-pushed the initial-implementation branch from 0344bfb to ee140da Compare October 25, 2016 16:48
@NullVoxPopuli
Copy link
Collaborator Author

I don't remember the status of this PR :-\

@NullVoxPopuli
Copy link
Collaborator Author

Cleaning up my PRs. If this work is still desired, feel free to cherry-pick

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants