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

**URL:** https://meta.discourse.org/t/non-discovery-api-pagination/167330
**Category:** Development
**Tags:** rest-api
**Created:** [16.Октябрь.2020 01:14:36 UTC](https://meta.discourse.org/t/non-discovery-api-pagination/167330 "2020-10-16T01:14:36Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![angus](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/angus/32/341715_2.png) [@angus](https://meta.discourse.org/u/angus)
#### Post date: [16.Октябрь.2020 01:14:36 UTC](https://meta.discourse.org/t/non-discovery-api-pagination/167330/1 "2020-10-16T01:14:36Z")

</div>

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

### Контекст

Для ясности: под «контекстом обнаружения» я имею в виду пагинацию в `list_controller.rb` и `tags_controller.rb`, где используются похожие методы [`construct_url_with`](https://github.com/discourse/discourse/blob/master/app/controllers/list_controller.rb#L409) для генерации ссылок на предыдущую и следующую страницы.

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

### Паттерн

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

```plaintext
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`

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

```

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

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

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

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

### Предложение

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

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

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

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