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

Add page-based pagination to GraphQL #3175

Merged

Conversation

raoulclais
Copy link
Contributor

@raoulclais raoulclais commented Oct 15, 2019

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tickets fixes #2762, api-platform/api-platform#1152
License MIT
Doc PR N/A

This PR allows to use a page-based pagination using GraphQL instead of the default cursor-based pagination. This choice is made at operation/resource level.

@alanpoulain
Copy link
Member

Nice feature!
Could you add an entry in the CHANGELOG.md file please (in 2.6.0 with the PR number)?

collection {
id
}
paginationMetadata {
Copy link
Member

Choose a reason for hiding this comment

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

paginationInfo to be coherent with the pageInfo?

"""
Then the response status code should be 200
And the response should be in JSON
And the JSON node "data.fooDummies.collection" should have 1 elements
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
And the JSON node "data.fooDummies.collection" should have 1 elements
And the JSON node "data.fooDummies.collection" should have 1 element

And the JSON node "data.fooDummies.collection" should have 0 elements

@createSchema
Scenario: Retrieve a paginated collection using page-based pagination and client defined limit
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Scenario: Retrieve a paginated collection using page-based pagination and client defined limit
Scenario: Retrieve a paginated collection using page-based pagination and client-defined limit

Comment on lines 207 to 209
public function getGraphQlPaginationType(string $resourceClass = null, string $operationName = null): string
{
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);

return (string) $resourceMetadata->getGraphqlAttribute($operationName, 'paginationType', 'cursor', true);
}
Copy link
Member

Choose a reason for hiding this comment

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

An if $resourceClass or $operationName is null? Maybe they should not be nullable?

@@ -91,7 +93,10 @@ public function __invoke($itemOrCollection, string $resourceClass, string $opera
$data[$index] = $this->normalizer->normalize($object, ItemNormalizer::FORMAT, $normalizationContext);
}
} else {
$data = $this->serializePaginatedCollection($itemOrCollection, $normalizationContext, $context);
$paginationType = $this->pagination->getGraphQlPaginationType($resourceClass, $operationName);
Copy link
Member

Choose a reason for hiding this comment

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

Like above, this variable is not needed.

$info = $context['info'];

if (!($collection instanceof PaginatorInterface)) {
throw Error::createLocatedError(sprintf('Collection returned by the collection data provider must implement %s', PaginatorInterface::class), $info->fieldNodes, $info->path);
Copy link
Member

Choose a reason for hiding this comment

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

Please throw a \LogicException instead (see: https://github.com/api-platform/core/pull/3063/files).

$args = [
'page' => [
'type' => GraphQLType::int(),
'description' => 'The current page.',
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
'description' => 'The current page.',
'description' => 'Returns the current page.',

if ($itemsPerPageOptions['client_items_per_page']) {
$args[$itemsPerPageOptions['items_per_page_parameter_name']] = [
'type' => GraphQLType::int(),
'description' => 'The number of items per page.',
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
'description' => 'The number of items per page.',
'description' => 'Returns the number of items per page.',

'description' => 'Returns the elements in the list that come after the specified cursor.',
],
];
$paginationType = $this->pagination->getGraphQlPaginationType($resourceClass, $queryName);
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we should introduce a private method here (like getFilterArgs).

@mahmoodbazdar
Copy link
Contributor

@raoulclais Any news on this?

@alanpoulain alanpoulain merged commit bf8afd3 into api-platform:master Nov 19, 2019
@alanpoulain
Copy link
Member

Thank you @raoulclais! 🙂

norkunas pushed a commit to norkunas/core that referenced this pull request Dec 2, 2019
* Add page-based pagination to GraphQL

* Use page_parameter_name


Co-authored-by: Alan Poulain <contact@alanpoulain.eu>
@jpierront
Copy link
Contributor

@raoulclais @alanpoulain Hum, any object properties except "id" return a "null" value. If the property is nullable, it return null. If the property is not nullable it crash.

The query:

query getItems {
  items(page: 1, itemsPerPage: 12) {
    collection {
      id
      name
    }
  }
}

With a not null but nullable property:

{
  "data": {
    "items": {
      "collection": [
        {
          "id": "/api/items/1",
          "name": null
        }
      ]
    }
  }
}

With a not null and not nullable property:

  "errors": [
    {
      "debugMessage": "Cannot return null for non-nullable field Item.name.",
      "path": [
        "items",
        "collection",
        0,
        "name"
      ],
      "trace": [
        {
          "file": ".../vendor/webonyx/graphql-php/src/Executor/ReferenceExecutor.php",
          "line": 723,
          "call": "GraphQL\\Executor\\ReferenceExecutor::completeValue(GraphQLType: String, instance of ArrayObject(1), instance of GraphQL\\Type\\Definition\\ResolveInfo, array(4), null)"
        },
    }
  ]

@alanpoulain
Copy link
Member

@jpierront you're right, I fixed it there: #3517.

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.

[Question] Pagination with GraphQL
4 participants