Какой лучший метод RESTful возвращает общее количество элементов в объекте?

Я разрабатываю службу REST API для большого сайта социальных сетей Im, в который участвует. Пока что он работает отлично. Я могу выдавать GET, POST, PUT и DELETE запросы на URL-адреса объектов и влиять на мои данные. Однако эти данные выгружаются (ограничено 30 результатами за раз).

Однако какой лучший способ RESTful получить общее количество участников, через мой API?

В настоящее время я выдаю запросы к структуре URL-адреса, например:

  • /api/members - возвращает список участников (30 за раз, как указано выше)
  • /api/members/1 -Аффект одного члена, в зависимости от используемого метода запроса

Мой вопрос: как я мог бы использовать аналогичную структуру URL, чтобы получить общее количество участников в моем приложении? Очевидно, что запрос только поля id (аналогичный API-интерфейсу Facebooks) и подсчет результатов будет неэффективным, если только только половина результатов будет возвращена только.

Ответ 1

В то время как ответ на/API/пользователи выгружается и возвращает только 30 записей, ничего не мешает вам включить в ответ также общее количество записей и другую соответствующую информацию, такую ​​как размер страницы, номер страницы/смещение и т.д.

API StackOverflow - хороший пример того же проекта. Здесь документация для метода Users - https://api.stackexchange.com/docs/users

Ответ 2

Я предпочитаю использовать HTTP-заголовки для такого рода контекстуальной информации.

Для общего количества элементов я использую заголовок X-total-count.
Для ссылок на следующую, предыдущую страницу и т.д. Я использую http link header:
http://www.w3.org/wiki/LinkHeader

Github делает то же самое: https://developer.github.com/v3/#pagination

По-моему, он более чистый, так как он может использоваться также при возврате содержимого, которое не поддерживает гиперссылки (например, бинарные файлы, изображения).

Ответ 3

Альтернатива, если вам не нужны фактические элементы

Ответ Franci Penov - это, безусловно, лучший способ, чтобы вы всегда возвращали предметы вместе со всеми дополнительными метаданными о запрошенных вами сущностях. То, как это должно быть сделано.

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

/api/members?metaonly=true
/api/members?includeitems=0

или что-то подобное...

Ответ 4

Вы можете вернуть счет как пользовательский HTTP-заголовок в ответ на запрос HEAD. Таким образом, если клиенту требуется только подсчет, вам не нужно возвращать фактический список, и нет необходимости в дополнительном URL-адресе.

(Или, если вы находитесь в контролируемой среде от конечной точки до конечной точки, вы можете использовать собственный HTTP-глагол, такой как COUNT.)

Ответ 5

В последнее время я занимаюсь некоторыми обширными исследованиями этого и других вопросов, связанных с поисковым вызовом REST, и подумал, что это конструктивно, чтобы добавить некоторые мои выводы здесь. Я немного расширяю вопрос, чтобы включить мысли о пейджинге, а также счет, поскольку они связаны друг с другом.

Заголовки

Метаданные подкачки включаются в ответ в виде заголовков ответов. Большим преимуществом такого подхода является то, что сама полезная нагрузка ответа - это просто запрос, который запрашивал фактический запрос данных. Более легкая обработка ответов для клиентов, которые не заинтересованы в информации поискового вызова.

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

X-Total-Count

X-Total-Count: 234

Это используется в some API, который я нашел в дикой природы. Существуют также пакеты NPM для добавления поддержки этого заголовка, например. Loopback. Некоторые статьи рекомендуют также установить этот заголовок.

Он часто используется в сочетании с заголовком Link, что является довольно хорошим решением для поискового вызова, но не содержит общей информации о счете.

Ссылка

Link: </TheBook/chapter2>;
      rel="previous"; title*=UTF-8'de'letztes%20Kapitel,
      </TheBook/chapter4>;
      rel="next"; title*=UTF-8'de'n%c3%a4chstes%20Kapitel

Я считаю, что, читая много на эту тему, общий консенсус заключается в том, чтобы использовать заголовок Link для предоставления пейджинговых ссылок на клиентов, использующих rel=next, rel=previous и т.д. Проблема заключается в том, что ему не хватает информации о количестве общих записей, поэтому многие API сочетают это с заголовком X-Total-Count.

Альтернативно, некоторые API и, например, JsonApi, используйте формат Link, но добавьте информацию в конверт ответа вместо заголовка. Это упрощает доступ к метаданным (и создает место для добавления общей информации о счете) за счет увеличения сложности доступа к фактическим данным (добавлением конверта).

Content-Range

Content-Range: items 0-49/234

Продвижение статьи в блоге под названием Заголовок диапазона, я выбираю вас (для разбивки на страницы)!. Автор делает большой аргумент в пользу использования заголовков Range и Content-Range для разбивки на страницы. Когда мы внимательно прочитаем RFC в этих заголовках, мы обнаруживаем, что расширение их значения за пределами диапазонов байтов фактически ожидалось RFC и явно разрешено. При использовании в контексте items вместо bytes заголовок Range фактически дает нам способ как запросить определенный диапазон элементов, так и указать, к какому диапазону итогового результата относятся элементы ответа. Этот заголовок также дает отличный способ показать общее количество. И это истинный стандарт, который в основном отображает "один к одному" на пейджинг. Это также используется в дикой природе.

Конверт

Многие API-интерфейсы, в том числе из нашего любимого веб-сайта Q & используют конверт, обертку вокруг данных, которые используются для добавления метаинформации о данных. Кроме того, OData и JsonApi стандарты используют конверт ответа.

Большой недостаток этого (imho) заключается в том, что обработка данных ответа становится более сложной, поскольку фактические данные должны быть найдены где-то в конверте. Также есть много разных форматов для этого конверта, и вы должны использовать правильный. Это говорит о том, что отклики ответа от OData и JsonApi сильно отличаются друг от друга, смешивая OData в метаданных в нескольких точках ответа.

Отдельная конечная точка

Я думаю, что это было достаточно полно рассмотрено в других ответах. Я не расследовал это, потому что согласен с комментариями, что это путает, поскольку у вас теперь есть несколько типов конечных точек. Я думаю, что это красиво, если каждая конечная точка представляет собой (набор) ресурсов (ов).

Дальнейшие мысли

Мы не только должны сообщать метаинформацию поискового вызова, связанную с ответом, но также разрешать клиенту запрашивать конкретные страницы/диапазоны. Интересно также взглянуть на этот аспект, чтобы в итоге получить согласованное решение. Здесь также можно использовать заголовки (заголовок Range кажется очень подходящим) или другие механизмы, такие как параметры запроса. Некоторые люди выступают за обработку страниц результатов в виде отдельных ресурсов, что может иметь смысл в некоторых случаях использования (например, /books/231/pages/52). В итоге я выбрал дикий диапазон часто используемых параметров запроса, таких как pagesize, page[size] и limit etc в дополнение к поддержке заголовка Range (и как параметр запроса также).

Ответ 6

Я бы рекомендовал добавлять заголовки для них, например:

HTTP/1.1 200

Pagination-Count: 100
Pagination-Page: 5
Pagination-Limit: 20
Content-Type: application/json

[
  {
    "id": 10,
    "name": "shirt",
    "color": "red",
    "price": "$23"
  },
  {
    "id": 11,
    "name": "shirt",
    "color": "blue",
    "price": "$25"
  }
]

Подробнее см.

https://github.com/adnan-kamili/rest-api-response-format

Для файла swagger:

https://github.com/adnan-kamili/swagger-response-template

Ответ 7

Как насчет новой конечной точки > /api/members/count, которая просто вызывает Member.Count() и возвращает результат

Ответ 8

Кажется проще всего добавить

GET
/api/members/count

и вернуть общее количество членов

Ответ 9

Иногда фреймворки (например, $resource/AngularJS) требуют массива в качестве результата запроса, и вы не можете иметь такой ответ, как {count:10,items:[...]}, в этом случае я храню "count" в responseHeaders.

Р. S. Фактически вы можете сделать это с помощью $resource/AngularJS, но для этого нужны некоторые настройки.

Ответ 10

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

Я предпочитаю иметь отдельную конечную точку для count (или такую ​​же конечную точку с параметром countOnly). Поскольку вы можете подготовить конечного пользователя к длительному/трудоемкому процессу, показывая правильно подготовленную панель прогресса.

Если вы хотите вернуть данные в каждом ответе, должно быть указано значение pageSize, а также смещение смещения. Честно говоря, лучшим способом является повторение фильтров запросов. Но ответ стал очень сложным. Поэтому я предпочитаю выделенную конечную точку для возврата счетчика.

<data>
  <originalRequest>
    <filter/>
    <filter/>
  </originalReqeust>
  <totalRecordCount/>
  <pageSize/>
  <offset/>
  <list>
     <item/>
     <item/>
  </list>
</data>

Couleage my, предпочитаю параметр countOnly для существующей конечной точки. Таким образом, при указании ответ содержит только метаданные.

конечная точка? = Значение фильтра

<data>
  <count/>
  <list>
    <item/>
    ...
  </list>
</data>

конечная точка фильтра = значение &? CountOnly = истина

<data>
  <count/>
  <!-- empty list -->
  <list/>
</data>