Skip to content
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

Present with multiple entities #241

Closed
adamgotterer opened this issue Sep 7, 2012 · 24 comments
Closed

Present with multiple entities #241

adamgotterer opened this issue Sep 7, 2012 · 24 comments

Comments

@adamgotterer
Copy link
Contributor

The response would be the combination of two entities. I've run into this issue with things like pagination blocks. I've had to hack around with body to get something like:

{
  "users": [...],
  "pagination": {
    "page": 1,
    "num_pages": 1000
  }
}

Would be interesting to have a "present multi" feature. Maybe something along the lines of:

present_multi [[ @coupons, with: Entities::Users], [ @pagination, with: Entities::Pagination, root: 'pagination' ]]

Would love to start a discussion and hear other peoples thoughts?

@dblock
Copy link
Member

dblock commented Sep 8, 2012

It's a common pattern that a lot of people like in their API. I would extend the existing present and evaluate the right-hand-side parameter type to figure out whether this is a multiple or a single present type.

@adamgotterer
Copy link
Contributor Author

Do you like the array syntax?

present [[ @coupons, with: Entities::Users], [ @pagination, with: Entities::Pagination, root: 'pagination' ]]

@dblock
Copy link
Member

dblock commented Sep 10, 2012

Not as much as I like hashes :)

Seems like all those array structures are redundant. This could be a 2-parameter function

def present(variable, * options)
...
end
present @coupons, with: Entities::Users, root: 'pagination'

@adamgotterer
Copy link
Contributor Author

How would you know when the first entities options ends and the second begins?

@dblock
Copy link
Member

dblock commented Sep 10, 2012

In Ruby this is called splat. It's one of my personal favorite features :)

@adamgotterer
Copy link
Contributor Author

I'm familiar with splat. So please excuse my ignorance, but I'm not sure I follow how the syntax would work with multiple variables and options? My array syntax lets you customize the present for each variable separately. Can you convert this example?

present [[ @users, with: Entities::Users, root: 'users' ], [ @pagination, with: Entities::Pagination, root: 'pagination' ]]

@dblock
Copy link
Member

dblock commented Sep 10, 2012

I guess I didn't include the most important part in my answer :)

{
   users: present @users, with: ...
   pagination: present @pagination, with ...
   ...
}

Rather than a top-level present.

@adamgotterer
Copy link
Contributor Author

That makes a lot more sense :) Definitely cleaner then mine. I'll see if I have some time over the next week or so to implement.

@dblock
Copy link
Member

dblock commented Sep 23, 2012

@adamgotterer I'll be releasing a new Grape version soon, LMK how close/far this is.

@adamgotterer
Copy link
Contributor Author

I haven't had a chance to work on this yet, been pretty busy. When is the next version out?

@bobbytables
Copy link
Contributor

@dblock @adamgotterer Are you thinking that in the resource you'd have

get '/users' do
  {
    users: present @users, with: UserEntity,
    pagination: present @pagination, with: PaginationEntity
  }
end

Just trying to get a feel for this feature.

@dblock
Copy link
Member

dblock commented Oct 8, 2012

Yes, that would look good!

@bobbytables
Copy link
Contributor

I feel this breaks a few things in terms of "who's responsible for what". The grape entities, from my point of view, is the view layer in grape. While this syntax makes sense, I feel like it's giving mixed responsibility for the resource. Because now it relies on how you format data in 2 places.

I think a better solution could be an entity method that excepts "top-level" exposures OR
allow resources to do multiple present calls.

present @users, with: UserEntity
present @pagination, with: PaginationEntity

Would yield:

{
  users: [...]
  pagination: {...}
}

@mbleigh
Copy link
Contributor

mbleigh commented Oct 8, 2012

What about an optional symbol/string first argument that defines a key on a root hash, e.g.

present :users, @users, with: UserEntity
present :pagination, @pagination, with: PaginationEntity

Of course existing functionality should remain working as-is.

@bobbytables
Copy link
Contributor

Or:

present @users, as: :users, with: UserEntity
present @pagination, as: :pagination, with: PaginationEntity

@dblock
Copy link
Member

dblock commented Oct 9, 2012

Without the { } we'll be saying that multiple things are being returned. And they can be returned from multiple places! I think that the extra curly braces are more predictable, but don't take my word for it :)

@dblock
Copy link
Member

dblock commented Oct 9, 2012

And note that this is not a compilable hash, you can't make a key a function.

{
 present :users, @users, with: UserEntity,
 present :pagination, @pagination, with: PaginationEntity
}  

@marcusg
Copy link
Contributor

marcusg commented Nov 8, 2012

hey guys, any progress here?

@adamgotterer
Copy link
Contributor Author

I've been insanely busy and haven't found any time to make contributions the last two months :( It's still on my todo, but if someone wants to take a stab at it, it's fine with me. Sorry for the delay, I know people are looking forward to this.

@niedhui
Copy link
Contributor

niedhui commented Apr 28, 2013

Hi guys, I came to this recently.

When using other gems , like acts_as_api, all object respond to a method as_api_response, so when we want to present a hash, just say render({page: 1, users: users }, :the_template), this is what came to my head first.

As grape-entity doing this by introduce a Entity decorator , what I do now is

  {
    page: 1,
    users: users.map {|user| UserEntity.new(user)}
  }

a little verbose.....

so I want a DSL, I prefer to what @mbleigh describe

  present :users, @users, with: UserEntity
  present :pagination, @pagination, with: PaginationEntity

It's easy to implement, and can be compatible.But if the result is

  {
    page: 1
    total_page: 2
    users: users
  }

we had to write three lines

  present :page, 1
  present :total_page, 2
  present :users, users, with: UserEntity

If choosing the hash way

{
   page: 1 ,
   total_page: 2,
   users: present @users, with: ...
}

each present in the hash value may need another option to tell it just return the value, not set to the body, Right?

I can do the two implementions in the next few days, leaving the choice to the developer if nobody had working with this

@dblock
Copy link
Member

dblock commented May 22, 2013

Implemented on HEAD. Thanks @niedhui.

@dblock dblock closed this as completed May 22, 2013
@calfzhou
Copy link
Contributor

Sorry to ping on this old issue, but i have one more question about desc.success.

Yes, now i can place multiple presents to expose pagination info along with the data collection, but how can i set this to desc.success? It only allows one entity -_-

@dblock
Copy link
Member

dblock commented Feb 10, 2015

@calfzhou I don't think I understand. Can you restate it in a new thread on the Grape mailing list?

@birla22v
Copy link

birla22v commented Dec 5, 2016

I'm sorry to comment on this closed issue but I'm running into the same issue that @calfzhou had. Was there a solution discussed for it?

Thank you!

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

No branches or pull requests

8 participants