-
Notifications
You must be signed in to change notification settings - Fork 14
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
Delegate to Roar's represent w/o options argument #18
base: master
Are you sure you want to change the base?
Conversation
Small change that seems to grant us all of the niceties of Roar's represent for free
813eb59
to
ce70c06
Compare
Not sure what's up with that failure, seems intermittent maybe? Looks like it's having trouble downloading some ruby version. |
I like this change. It needs documentation, tests, and a CHANGELOG entry. You should fix the build too, use |
@dblock - Ok, I added specs to cover the array usage. Before I make an entry in the CHANGELOG and README.md though, there's a problem though that I need advice on... An example in README.md no longer works, specifically: module ProductsRepresenter
include Roar::JSON::HAL
include Roar::Hypermedia
include Grape::Roar::Representer
collection :entries, extend: ProductRepresenter, as: :products, embedded: true
end get 'products' do
present Product.all, with: ProductsRepresenter
end The problem is that it now taps into However, aside from it being breaking behavior, I think this is a good change. Apologies if I fumble on the terminology a bit here, but an array of resources is not a resource and does not deserve the ability to define its own rels. An array is essentially a primitive type and has no meaning except as a property of some other resource. To be clear, this brings I think the only way you could do it is if you extended the array itself with the representer and then presented it without the Note that tests around If it wasn't described in README.md already then I'd categorize it as a fixed bug that people may be improperly depending on in their code, and is thus still a breaking change, but for the better since they should represent those arrays as proper resources with a class rather than just a floating array. I'm very interested to hear your take on it though. Sorry that this is turning out to be a bother. |
As per feedback in PR I had to move things around a little bit in the example representers because using the request url as the self rel only works if the resource will always be presented by itself It's still a useful example to have to demonstrate how using `env` works though, so I made sure to move it into a resource that fits that criteria.
ed40c7d
to
c4d0f6c
Compare
Hmmmm, this is kinda a big deal. I've seen this kind of usage in many places, I definitely use it all over the place, like here. I guess the question is, how does one present a collection of objects in the new world? |
Well, you can still present an array of resources... It's actually exactly the same you just can't write a representer for the array itself, so if you want to make a self rel to the array you cannot. Luckily, README.md did not do this in the example, so the above quoted example would be accomplished I think identically by simply: get 'products' do
present Product.all, with: ProductRepresenter #NB Product not Products
end It will then render that as a JSON array of resources (as described in my spec additions). |
So in a nutshell, it's an easy fix if you're using barebone collection representers for your barebone arrays... Just delete the representer and reference the singular resource representer instead. Requires code change but results in less code. The tricky part is if people are treating barebone arrays as formalized rels, but they're hypermedia-ing wrong in that case. Also for your linked example it's the former, you'd just need to delete that |
I don't think we want an array of hypermedia representations. A lot of times you want other fields in there, such as I don't want to make a change like this irresponsibly, I'd like to leave this open and see if other people comment. I'll do a code review of course either way. You might want to look for a way to keep the old functionality though, basically have it both ways. |
Along with README and CHANGELOG make sure to write an UPGRADING with a section about what's affected. |
spec/decorator_spec.rb
Outdated
|
||
it 'returns an array of hypermedia representations' do | ||
get 'users' | ||
expect(last_response.body).to eq '[{"name":"Texassee","id":1,"links":[{"rel":"self","href":"/user/1"}]},{"name":"Lonestar","id":2,"links":[{"rel":"self","href":"/user/2"}]}]' |
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.
Expand the string into a Hash and compare JSON.parse
to that, so it's more readable, multiple lines, etc.
"but they're hypermedia-ing wrong in that case." - I personally feel the opposite way, I wonder what a library like Hyperclient "thinks" when it sees a plain array of hypermedia responses? Maybe this can/should/has been brought up on the HAL mailing list? |
Ok, is it alright if I wait to change CHANGELOG, README.md, and the UPGRADING section until the changes are approved? I'll try to think of a way to maintain previous behavior... But I don't know if it's possible without forcing them to be explicit about automatically turning each array element into the specified representer, which kind of defeats the purpose of the PR since I was hoping it would bring |
I hear you @jcwilk, I am not saying this is a bad idea, I just see unintended (or intended) consequences that aren't going to make people happy. |
Also maybe write a failing spec here for the array representers scenario, I'll try to help fix. |
"I feel the opposite way, I wonder what a library like Hyperclient "thinks" when it sees a plain array of hypermedia responses?" - Well the thing is that there's two scenarios: 1 - It's an arbitrary array, has no inherent meaning, is not a relation from anything else, and is just a junk pile of elements which each are individually formalized with their own self rels but there's no coherent way to refer to collection of all of them in relation to anything else. 2 - It's a meaningful collection which represents a relation from something else, like all products ordered by a user, or all line items of an order, or something like that, and it deserves its own properties, a rel, and maybe even a self rel. For 1, IMO it should really simply be an array of hypermedia resources. IIRC (it's been awhile) clients vary on how they handle this, the more flexible ones go "hey, this is an array of resources... I know how to handle resources, and arrays are simple." You could maybe get purist about it and try to think of some overarching meaning of all existing products to turn it into a resource, but I'm a little out of my element here about what is and isn't correct and it gets a little philosophical. For 2, it's more straightforward and is just a normal hypermedia rel. |
Sure, I can write a failing spec. |
it 'returns a hypermedia representation' do | ||
get '/product/666' | ||
expect(last_response.body).to eq '{"title":"Lonestar","id":"666","links":[{"rel":"self","href":"http://example.org/product/666"}]}' | ||
context 'with an array of resources as a resource' do |
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.
@dblock - failing spec here
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, I'll try to spend some time on this.
Small change that seems to grant us all of the niceties of Roar's represent for free.
The main thing I was running into that
Grape::Roar
does not support but thatRoar
does support is doing things like...Since
Grape::Roar
never calls https://github.com/apotonick/representable/blob/master/lib/representable/represent.rb#L3 so theRepresentable::ForCollection
stuff isn't utilized, along presumably with any other features included in https://github.com/apotonick/representable/blob/master/lib/representable.rb#L22-L27 but they seem less exciting than being able to pass in an array of objects.Only other way I can seem to figure to be able to represent an array of objects is to make a whole separate representer class just for a plural version of a resource, which seems really verbose.
Specs still pass fine. Let me know if you want me to add a spec for the array stuff, though I guess I see this as generally tapping into
Representable
in a more complete way... Which you can't really write a test for, but if you think testing for enabling arrays specifically is valuable I can throw one in, lmk.