Пагинация API без обнаружения

Недавно я работал с API groups и у меня возникли некоторые мысли по поводу пагинации, особенно в контексте, отличном от контекста обнаружения (discovery context).

Контекст

Для ясности: под «контекстом обнаружения» я имею в виду пагинацию в list_controller.rb и tags_controller.rb, где используются похожие методы construct_url_with для генерации ссылок на предыдущую и следующую страницы.

Кстати, эти методы construct_url_with можно было бы объединить в подключаемый модуль, поскольку они довольно похожи. Однако эта пагинация тесно связана с генерацией списков тем, поэтому это отдельная категория.

Паттерн

В контексте, отличном от контекста обнаружения, пагинация использует вариант следующего кода:

page = params[:page].to_i
page_size = 38
items = items.offset(page * page_size).limit(page_size)

Этот паттерн можно встретить в различных контроллерах, например (список не полный):

  • groups
  • web hooks
  • emails
  • notifications
  • directory items
  • staff action logs

При использовании этих конечных точек (endpoints) из стороннего клиента возникает несколько проблем с пагинацией.

Проблемы

Частная: включение URL «загрузить ещё»

Некоторые из этих конечных точек возвращают URL «загрузить ещё» (со ссылкой на «следующую» страницу), даже если дальнейших страниц нет.

Например, на meta я вижу 9 групп. Однако в .json для этой страницы будет запись load_more_groups с несуществующей второй страницей (нумерация страниц фактически начинается с 0, поэтому страница «1» — это вторая страница):

https://meta.discourse.org/g.json

...
"total_rows_groups":9,
"load_more_groups":"/groups?page=1"

Это можно было бы назвать «ошибкой» конечной точки, так как клиент API часто пытается использовать URL «загрузить ещё» при переборе страниц, вместо того чтобы самостоятельно обрабатывать подсчёт страниц.

Общая: разная терминология, обработка размера страницы и возвращаемые данные пагинации

В более общем плане в контекстах, отличных от контекста обнаружения, наблюдается значительная вариативность в терминологии пагинации, размерах страниц и возвращаемых данных пагинации. Например:

  • Параметр «page» называется либо :page, либо :offset.
  • «Общее количество элементов» иногда включается как total_rows_*, однако это не всегда так, и иногда используется другое название.
  • Большинство размеров страниц назначаются локальным переменным в соответствующих действиях и немного различаются, из-за чего приходится искать их вручную.

Предложение

Разумеется, у многих из поднятых мной вопросов есть свои причины. Многие конечные точки, не относящиеся к контексту обнаружения, потребляются в основном (или исключительно) клиентом приложения Discourse и адаптированы под него. Это логично.

Тем не менее, возможно, стоит начать постепенный переход к стандартизации пагинации в контекстах, отличных от контекста обнаружения, особенно для конечных точек, которые часто используются внешними клиентами (например, groups). Это также упростит решение таких проблем, как включение URL «загрузить ещё».

По сути, я представляю себе модуль «Pagination», который формализует этот паттерн и мог бы обрабатывать пагинацию для некоторых выбранных конечных точек, возможно, начав с Groups.

Я мог бы создать PR по этому поводу, но сначала хотел поднять эту тему для обсуждения.

5 лайков