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

Pagination of nested resources #214

Open
Cohedrin opened this issue Jan 16, 2017 · 5 comments
Open

Pagination of nested resources #214

Cohedrin opened this issue Jan 16, 2017 · 5 comments

Comments

@Cohedrin
Copy link

Is it currently possible to paginate relationships? From what I found in the code and the docs, this doesn't seem to be officially supported anywhere.

The best solution I could come up with is override the relationships callback and manually inject the links into the relationship struct, but in that case there's no way to determine what page we should paginate to.

@alanpeabody
Copy link
Contributor

I have typically relied on links only when needing to paginate a relationship. The initial link has always been to the first page then I let the other controller take over the pagination. What is your use case exactly?

@Cohedrin
Copy link
Author

Specific use case is something like this:

  • Post has_many comments
  • Comments can be very long
    • Ideally, would be able to hit something like /posts/1/comments?page=2 and get the second page of comments for that particular post

The response should ideally look something like the suggestion here

I have typically relied on links only when needing to paginate a relationship.

What do you mean by this? Does your serializer look something like this?

  has_many :comments, serializer: MyApp.CommentSerializer, include: true, links: [
    next: "posts/:id/comments?page=2"
  ]

If that is what you mean, the major issues I found with this are:

  1. No way of adding meta info to the relationship object. For example a common use case (as suggested by the json-api spec itself) is to add a current_page and total_pages field to the meta object, to make display for the user easier. Though I believe this will be addressed by Resource Identifier metadata #206
  2. This will always add the next page option, regardless of whether or not there are actually enough elements to span to the next page, since it's hardcoded in.

@alanpeabody
Copy link
Contributor

alanpeabody commented Jan 16, 2017

@Cohedrin That is what I mean, however I have never included a relationship that would be paginated, so the link was always just to page 1. (I very rarely include has_many relationships unless forced.)

If you pass an :atom as the link it should be treated as a function that can be used to generate a url, eg:

has_many :comments, serializer: CommentSerializer, include: true, links: [next: :next_link]

def next_link(post, opts) do
  # whatever pagination logic etc.
  # just return either a link or nil
end

FWIW: This library doesn't really handle the /relationships style rendering as mentioned in that post - I honestly have never had a real use for it.

Also RE #206 that is currently only per resource identifier meta (eg per item in data), not relationship level meta that you are looking for.

Let me know if that helps at all!

@Cohedrin
Copy link
Author

Cohedrin commented Jan 16, 2017

I see. That does clear things up, thank you.

The next_link method option is pretty much what I'm looking for, however it's going to generate an extra query since we can't pass a prepaginated scrivener instance, at least not as far as I can tell.

Perhaps the best way to solve a problem like this would be to add a way of passing arbitrary variables to the serializer. Something akin to AMS's arbitrary variables.

Maybe something like:

# controller 
def show do
  json(conn, JaSerializer.format(Serializer, data, conn, instance_opts: %{comments: [] }))
end


# Serializer 
defmodule MyApp.Serializer do
  attributes [:id]

  has_many :comments, ...
   
  def comments(post, conn, instance_opts) do
    # pagination logic here
    # comments = instance_opts.comments
  end
end

I realize this could be done by setting some values in the connection object, but adding values to the connection struct seems a bit weird when they'll only be used in the serializer.

Would you be open to a pr that does this?

@marcelotto
Copy link

+1 on adding arbitrary options

I also have the need for pagination of included relationships, but the arbitrary options would also help me with another issue I have: the relationships in my case, are computed with a quite complex query. Executing this query in the relationship callback is not a good solution for me, since the relationship callback for included relationships is called twice (one time from JaSerializer.Builder.ResourceIdentifier.build/2 and again from JaSerializer.Builder.Included.resources_for_relationship/4), which might be viable for the usual preload, but not for performing arbitrary queries. With the arbitrary options solution, one could perform such queries in the controller, where they belong to anyways IMO.

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

4 participants