Graphene and Relay example GraphQL pagination API and UI
This describes 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!
I created a github repo with 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.
Graphene GraphQL backend¶
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
$ git clone https://github.com/saltycrane/graphene-relay-pagination-example.git $ cd graphene-relay-pagination-example $ 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 } } } }
GraphiQL query screenshot
$ ./manage.py graphql_schema --schema pagination_ex_api.schema.schema --out ../schema.graphql
React Relay Next.js frontend¶
In addition to Relay, React, and TypeScript, the frontend UI uses relay-hooks, Next.js, and reactstrap. It takes advantage of Relay fragments and Next.js routing to store pagination state. Server-side rendering (SSR) is disabled because it's difficult to set up and isn't important for this example.
Install Node.js 14
Install packages and run dev server
$ cd react-relay-webapp $ npm install $ npm run devserver
Go to http://127.0.0.1:3000 in the browser
Links to code¶
My backend code- /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
Related posts
- How to use ast-grep with GraphQL — posted 2024-09-24
- Next.js App Router (RSC) projects w/ open source code — posted 2024-07-30
- Next.js Relay GraphQL Pokemon example — posted 2024-05-22
- Example Node.js Passport.js SAML app using OneLogin — posted 2024-05-10
- Aphrodite to CSS Modules codemod — posted 2022-12-09
- Simple codemod example with jscodeshift — posted 2021-05-03