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

[RFC] feat(paginator): add CursorPaginatorInterface #6305

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

priyadi
Copy link
Contributor

@priyadi priyadi commented Apr 11, 2024

Q A
Branch? main
Tickets
License MIT
Doc PR

This is currently a WIP and an RFC. If maintainers are open to the idea, I will complete the PR. Currently, it is missing HAL supports and the tests.

To improve cursor pagination, I propose the creation of CursorPaginatorInterface:

interface CursorPaginatorInterface extends \Countable, \Traversable
{
    public function getNextPageCursor(): ?string;
    public function getPreviousPageCursor(): ?string;
    public function getFirstPageCursor(): ?string;
    public function getLastPageCursor(): ?string;
}

A cursor is an opaque identifier embedded in the URL, that indicates a specific page. The format of this identifier is left to the implementation. The framework and the user should not care about this format, they only know that the identifier can be used to locate a page.

A future DoctrineCursorPaginatorFactory might use a Base64-encoded serialized array containing the edge values and sort direction.

If a ProviderInterface::provide() returns a CursorPaginatorInterface, API Platform will render it like this (for JSON-LD/Hydra):

{
  "@context": "/api/contexts/Book",
  "@id": "/api/books",
  "@type": "hydra:Collection",
  "hydra:member": [
     ...
  ],
  "hydra:view": {
    "@type": "hydra:PartialCollectionView",
    "@id": "/api/books",
    "hydra:first": "/api/books",
    "hydra:last": "/api/books?page=q1YqU7KKjtVRKlCy0jXUUcpRssorzcnRUcpXsjLQUSpRslIqVaoFAA",
    "hydra:next": "/api/books?page=q1YqU7KqVspMUbKyNKjVUSpQsjLRUcpRssorzcnRUcpXsjLQUSpRsgIK1QIA",
    "hydra:previous": "/api/books?page=q1YqU7KqVspMUbIyM6zVUSpQsjLSUcpRssorzcnRUcpXsjLQUSpRslIqVaoFAA"
  }
}

It reuses the same page_parameter_name as PartialPaginatorInterface. My PR changes the type of these page parameters from integer to string for this to work. It should still work for PartialPaginatorInterface.

Cursor pagination will be decoupled from filtering, and no longer requires filters to work.

In the future, it will be possible to create an adapter from PaginatorInterface and PartialPaginatorInterface to CursorPaginatorInterface. In which case, the page numbers will be treated the same way as cursors. Then, we'll be able to handle all the paginators using a single logic.

In the future, we should also be able to remove many of the GraphQL-related special cases and simplify the code base.

Included in this PR:

  • CursorPaginatorInterface
  • CursorBasedPartialCollectionViewNormalizer. I decided to make it separate from PartialCollectionViewNormalizer for simplification.
  • Change to OpenApiFactory so that the page query parameters' type is string, not integer.
  • CursorPagination
  • Support for HAL

Copy link

stale bot commented Jun 11, 2024

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

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

Successfully merging this pull request may close these issues.

2 participants