Недавно я решил использовать GraphQL для API, который разрабатываю, и столкнулся с путаницей по поводу того, как реализовать разбиение на страницы на основе курсора, и обобщил здесь свои выводы для использования другими.

Я начал с ознакомления со справочной документацией по подкачке страниц:
http://graphql.org/learn/pagination/

Затем я просмотрел альфа-документацию GitHub: https://developer.github.com/early-access/graphql/

Пример GitHub показывает их запрос с использованием ребер с одинаковыми аргументами first и after. В целом он, похоже, полностью соответствовал рекомендациям официальных документов GraphQL. Я решил, что попробую реализовать разбиение по страницам для моего API с помощью курсоров, как для гибкости, так и в качестве обучающего эксперимента.

Проверьте их API в проводнике:
https://developer.github.com/early-access/graphql/explorer/

(В статье GraphQL курсоры звучат как лучшее решение во всех случаях, но если потребителям API нужен способ перехода на определенную страницу без предварительного запроса, вам нужно будет использовать числовые смещения, поэтому обязательно оцените и выберите лучшее решение для вас. В моем случае я решил реализовать API для разбиения по страницам на основе курсора и смещения, чтобы я мог поддерживать оба типа клиентов.)

Некоторые ключевые моменты моей реализации:

  • Курсоры вычисляются во время выполнения и не сохраняются вместе с сущностью.
  • Курсоры - это результат других свойств объекта в кодировке base64, обычно это просто идентификатор.
  • При получении курсора в запросе он должен быть декодирован из base64 обратно в сериализованные свойства, а затем использован для поиска связанного элемента.

Я создал модуль нумерации страниц, чтобы закрепить эту логику:

Затем вы можете увидеть, как он используется в запросе с именем units ниже:

(Обратите внимание, что в моем примере выше я нахожу индекс элемента с id, совпадающим с идентификатором курсора. Это не рекомендуется, поскольку это операция O (N) для каждого запроса. Это работает только потому, что у меня есть весь набор данных в памяти, и это относительно небольшой. В более традиционном сервисе данные будут в базе данных с индексированными полями идентификатора, чтобы их можно было искать напрямую более эффективным способом. Ключевым моментом является то, что вы используете курсор, чтобы найти индекс элемента и затем выполните ту же технику нарезки, которую вы обычно делаете, если бы ваша реализация разбиения на страницы использовала стандартные skip / top или limit / offset.)

Теперь, если я отправлю запрос в свой API, например:

Я бы вернулся:

Надеюсь, что это внесет некоторую ясность в то, как реализовать разбиение по страницам на основе курсора с использованием GrahpQL. Дайте мне знать, если у вас есть предложения по улучшению.