Вопрос:
Я разрабатываю службу REST API для большого сайта социальных сетей Im, в который участвует. Пока что он работает отлично. Я могу выдавать GET, POST, PUT и DELETE запросы на URL-адреса объектов и влиять на мои данные. Однако эти данные выгружаются (ограничено 30 результатами за раз).
Однако какой лучший способ RESTful получить общее количество участников, через мой API?
В настоящее время я выдаю запросы к структуре URL-адреса, например:
- /api/members – возвращает список участников (30 за раз, как указано выше)
- /api/members/1 -Аффект одного члена, в зависимости от используемого метода запроса
Мой вопрос: как я мог бы использовать аналогичную структуру URL, чтобы получить общее количество участников в моем приложении? Очевидно, что запрос только поля id (аналогичный API-интерфейсу Facebooks) и подсчет результатов будет неэффективным, если только только половина результатов будет возвращена только.
Лучший ответ:
В то время как ответ на/API/пользователи выгружается и возвращает только 30 записей, ничего не мешает вам включить в ответ также общее количество записей и другую соответствующую информацию, такую как размер страницы, номер страницы/смещение и т.д.
API StackOverflow – хороший пример того же проекта. Здесь документация для метода Users – https://api.stackexchange.com/docs/users
Ответ №1
Я предпочитаю использовать HTTP-заголовки для такого рода контекстуальной информации.
Для общего количества элементов я использую заголовок X-total-count.
Для ссылок на следующую, предыдущую страницу и т.д. Я использую http link header:
http://www.w3.org/wiki/LinkHeader
Github делает то же самое: https://developer.github.com/v3/#pagination
По-моему, он более чистый, так как он может использоваться также при возврате содержимого, которое не поддерживает гиперссылки (например, бинарные файлы, изображения).
Ответ №2Содержание
- Альтернатива, если вам не нужны фактические элементы
- Заголовки
- X-Total-Count
- Ссылка
- Content-Range
- Конверт
- Отдельная конечная точка
- Дальнейшие мысли
Альтернатива, если вам не нужны фактические элементы
Ответ Franci Penov – это, безусловно, лучший способ, чтобы вы всегда возвращали предметы вместе со всеми дополнительными метаданными о запрошенных вами сущностях. То, как это должно быть сделано.
но иногда возвращение всех данных не имеет смысла, потому что они могут вообще не нуждаться в них. Возможно, все, что вам нужно, это метаданные о запрошенном ресурсе. Как общее количество или количество страниц или что-то еще. В таком случае вы всегда можете запросить URL-запрос, чтобы ваша служба не возвращала элементы, а просто метаданные:
/api/members?metaonly=true /api/members?includeitems=0
или что-то подобное…
Ответ №3
Вы можете вернуть счет как пользовательский HTTP-заголовок в ответ на запрос HEAD. Таким образом, если клиенту требуется только подсчет, вам не нужно возвращать фактический список, и нет необходимости в дополнительном URL-адресе.
(Или, если вы находитесь в контролируемой среде от конечной точки до конечной точки, вы можете использовать собственный HTTP-глагол, такой как COUNT.)
Ответ №4
В последнее время я занимаюсь некоторыми обширными исследованиями этого и других вопросов, связанных с поисковым вызовом 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 (и как параметр запроса также).
Ответ №5
Я бы рекомендовал добавлять заголовки для них, например:
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
Ответ №6
Как насчет новой конечной точки > /api/members/count, которая просто вызывает Member.Count() и возвращает результат
Ответ №7
Кажется проще всего добавить
GET /api/members/count
и вернуть общее количество членов
Ответ №8
Иногда фреймворки (например, $resource/AngularJS) требуют массива в качестве результата запроса, и вы не можете иметь такой ответ, как {count:10,items:[…]}, в этом случае я храню “count” в responseHeaders.
Р. S. Фактически вы можете сделать это с помощью $resource/AngularJS, но для этого нужны некоторые настройки.
Ответ №9
При запросе разбитых на страницы данных вы знаете (с помощью значения параметра размера страницы или значения размера страницы по умолчанию) размер страницы, поэтому вы знаете, получили ли вы все данные в ответ или нет. Когда в ответе меньше данных, чем размер страницы, вы получаете целые данные. Когда возвращается полная страница, вам нужно снова спросить о другой странице.
Я предпочитаю иметь отдельную конечную точку для 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>