This is an example GraphQL API using Relay connections to power a discretely paged Amazon-like pagination UI. Connections are designed for infinite-scroll UIs, however Artsy Engineering developed a solution to use them with discretely paged UIs as described in their article: Effortless Pagination with GraphQL and Relay? Really!
This repo contains an implementation of the Artsy pagination API in Graphene, Django, and Python and a corresponding web app using Relay, React, and TypeScript.
For a vanilla Graphene Relay pagination API for an infinite scroll UI, see my basic example.
The Artsy pagination API augments the Relay Connection type with an additional pageCursors
field that contains metadata used to implement the pagination UI. I ported their TypeScript code in artsy/metaphysics
and relay-cursor-paging
to Python using Graphene and Django.
Data is stored in a PostgreSQL database running in Docker. It is seeded with fish fixture data from ACNHAPI. Django is configured to log SQL queries to the console and show that SQL queries use COUNT
, LIMIT
, and OFFSET
. Example:
SELECT COUNT(*) AS "__count" FROM "fishes_fish";
SELECT "fishes_fish"."id", "fishes_fish"."description", "fishes_fish"."icon_url", "fishes_fish"."name", "fishes_fish"."price" FROM "fishes_fish" ORDER BY "fishes_fish"."name" ASC LIMIT 5 OFFSET 5;
-
Install Python 3.8
-
Install packages, set up database, and run dev server
$ cd graphene-api $ python3 -m venv venv $ source venv/bin/activate $ pip install -r requirements.txt $ docker-compose up -d $ ./bin/resetdb $ ./manage.py migrate $ ./manage.py loaddata fishes $ ./manage.py runserver
-
Go to http://127.0.0.1:8000/graphql/ in the browser
-
Run the following query:
{ allFishes(first: 5, orderBy: "name") { pageCursors { previous { cursor } first { cursor page } around { cursor isCurrent page } last { cursor page } next { cursor } } edges { cursor node { name } } } }
$ ./manage.py graphql_schema --schema pagination_ex_api.schema.schema --out ../schema.graphql
- /graphene-api/fishes/schema.py
- /graphene-api/artsy_relay_pagination/fields.py
- /graphene-api/artsy_relay_pagination/pagination.py
- https://github.com/artsy/metaphysics/blob/production--2021-01-22--15-05-38/src/schema/v2/fields/pagination.ts
- https://github.com/artsy/metaphysics/blob/production--2021-01-22--15-05-38/src/lib/helpers.ts#L90-L104
- https://github.com/darthtrevino/relay-cursor-paging/blob/v0.2.0/src/getPagingParameters.ts
- https://github.com/graphql/graphql-relay-js/blob/v0.5.4/src/connection/arrayconnection.js
- https://github.com/graphql-python/graphene-django/blob/v2.15.0/graphene_django/filter/fields.py
- https://github.com/graphql-python/graphene-django/blob/v2.15.0/graphene_django/fields.py#L132-L177
- https://github.com/graphql-python/graphql-relay-py/blob/v2.0.1/graphql_relay/connection/arrayconnection.py#L30-L104
In addition to Relay, React, and TypeScript, the frontend UI uses Next.js, and reactstrap. It takes advantage of Relay v11 hooks, Relay fragments and Next.js routing to store pagination state.
-
Install Node.js 14
-
Install Watchman
brew install watchman
-
Install packages and run dev server
$ cd react-relay-webapp $ npm install $ npm run dev
-
Go to http://127.0.0.1:3000 in the browser
Server-side rendering (SSR) is disabled because it's difficult to set up and isn't important for this example.