В REST, как должен обрабатываться запрос GET к операции findAll, когда ресурсы разбиты на страницы? - PullRequest
3 голосов
/ 09 февраля 2012

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

GET /foo?page=1

Вопрос в том, как мне обработать запрос getAll, например:
GET /foo

Получение возможности обнаружения / HATEOASПринимая во внимание, я вижу несколько вариантов:

  1. вернуть 405 метод не разрешен и включить заголовок ссылки на первую страницу: Link=<http://localhost:8080/rest/foo?page=0>; rel=”first“
  2. return 400 Плохой запрос и включает заголовок Link (такой же, как указано выше)
  3. return 303 См. Other на первую страницу с нумерацией страниц
  4. return a 200 ОК но на самом деле возвращает только первую страницу (и включает URI следующей страницы в ссылку): Link=<http://localhost:8080/rest/foo?page=1>; rel=”next“
    • note : я бы не хотелсделайте это, научившись не управлять для клиента по умолчанию, если они явно не просили об этом.

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

Ответы [ 3 ]

2 голосов
/ 09 февраля 2012

С точки зрения RESTful, я думаю, что совершенно нормально обрабатывать оба представления одинаково.Рассмотрим программное обеспечение с несколькими версиями, которые вы хотите загрузить, последняя из которых 3.8.Так что, если вы хотите получить последнюю версию, вы можете обращаться к ней с GET /software/version/latest.zip и GET /software/version/3.8.zip, пока не выйдет более новая версия.Таким образом, две разные ссылки указывают на один и тот же ресурс.

Мне нравится представлять себе нумерацию страниц практически одинаково.На первой странице всегда есть последние статьи.Поэтому, если не указан page -параметр, вы можете просто предположить, что он равен 1.

Подход с атрибутом rel идет в несколько ином направлении.Это создание Google, чтобы лучше справляться с проблемой дублирующегося контента, и в первую очередь считается, что оно используется для того, чтобы различать «главную» страницу и страницы пагинации.Вот как это можно использовать:

//first page:
<link rel="next" href="http://www.foo.com/foo?page=2" />

//second page:
<link rel="prev" href="http://www.foo.com/foo?page=1" />
<link rel="next" href="http://www.foo.com/foo?page=3" />

//third and last page:
<link rel="prev" href="http://www.foo.com/foo?page=2" />

Так что с точки зрения SEO это хорошая идея (и рекомендуется Google) использовать эти элементы.Они также прекрасно сочетаются с ориентированной на ресурсы идеей REST и гипермедиа-представлением ресурсов.

Выбрав одно из ваших предложений, я думаю, что 303 See Other - верный путь.Он был предназначен для использования в подобных целях и является хорошим способом канонизировать ваши ресурсы.Вы можете сделать их доступными через множество URI, но иметь один «реальный» URI для представления (например, программное обеспечение с разными версиями).

Согласно спецификации, ответ должен выглядеть примерно так:

303 See Other
Location: http:www.foo.com/foo?page=1

<a href="http:www.foo.com/foo?page=1">http:www.foo.com/foo?page=1</a>

Таким образом, вы предоставляете Location-заголовок с «реальным» представлением, а тело должно содержать гипертекстовый документ, ссылающийся на новый URI.Обратите внимание, что в соответствии со спецификацией клиент ожидает для отправки запроса GET на значение Location, но он не должен .


// РЕДАКТИРОВАТЬ в качестве ответа на ваш комментарий (да, это действительно плохая практика требовать что-то, не доказывая этого :-) - мой плохой!):

Google представил rel="next" и rel="prev" атрибутов в сентябре 2011 года в официальном блоге для веб-мастеров 1034 *.Они могут использоваться дополнительно (или в некоторых случаях вместо) к тегу rel="canonical" .

. По этим ссылкам вы можете найти различия между ними:

  • rel="next" и rel="prev" элементы ссылки означают "для обозначения взаимосвязи между URL-адресами компонентов в разбитой на страницы серии"
  • * rel="canonical" "позволяет публично указывать предпочитаемый вамиверсия URL "

Так что между ними есть небольшая разница.Таким образом, вы можете разбить вашу проблему на каноническую проблему: есть несколько URL-адресов, указывающих на один и тот же ресурс (/foo и foo?page=1, но у вас есть предпочтительная версия URL-адреса (foo?page=1). Итак, теперь есть несколькоопции для подхода RESTful:

  • Если в запросе не указан параметр page, используйте значение по умолчанию (например, 1) при его обработке. Я думаю, что в этом конкретном случае это нормальноиспользовать значение по умолчанию, даже если вы указали, что это плохая практика.
  • Ответьте с помощью 303 См. Другое , предоставив предпочтительный URL-адрес в Местоположение -header (как описано выше). Я думаю, * 3xx -ответ - лучший (и, скорее всего, RESTLY предназначенный) способ работы с дублированным / каноническим контентом.
  • Ответьте с помощью 400 Bad Request в случае, если вы хотите заставить клиента предоставить page -параметр (как объяснил zzzzBov в своем ответе).Обратите внимание, что этот ответ не имеет что-то вроде заголовка Location (как предполагается в вашем вопросе), поэтому объяснение, почему запрос не удался, и / или правильный URL-адрес (если он указан) долженперейти к объекту-сущности ответа.Также обратите внимание, что в соответствии со спецификацией этот ответ обычно используется, когда клиент отправляет неверное / некорректное представление (! Не URL!) Вместе с запросом PUT или POST.Так что имейте в виду, что это также может быть немного двусмысленным для клиента.

Лично я не думаю, что ваше предложение ответить 405 Метод не разрешен хорошая идея.Согласно спецификации, вы должны предоставить Разрешить -заголовок, перечисляющий разрешенные методы.Но какие методы могут быть разрешены на этом ресурсе?Я могу думать только о POST.Но если вы не хотите, чтобы клиент также POST ему, вы также можете ответить 403 Forbidden с объяснением, почему это запрещено, или 404 Не найдено , если вы не хотите сказать, почему это запрещено.Так что это может быть немного двусмысленно (на мой взгляд).

Использование link -элементов с упомянутыми rel -атрибутами, как вы предлагаете в своем вопросе, по сути не является "RESTful", потому чтогипермедиа, которая решается в представлении ресурса.Но ваша проблема (насколько я понимаю) состоит в том, что вы хотите решить, как ответить на конкретный запрос и какое представление обслуживать.Но все же это не совсем бессмысленно:

Вы можете рассматривать всю проблему SEO как побочный эффект использования rel="next/prev/canonical", но имейте в виду, что они также создают связность (как качествоналичие ссылок), что является одной из характеристик REST (см. диссертацию Роя Филдинга ).

Если вы хотите погрузиться в RESTful Web Services (что того стоит), я рекомендую прочитатькнига RESTful Web Services Леонарда Ричардсона и Сэма Руби.

2 голосов
/ 09 февраля 2012

Давайте начнем с того факта, что REST не является стандартным протоколом, подобным SOAP, это просто средство структурирования сервиса, аналогичное тому, как языки описываются как объектно-ориентированные.

При всем этом, я бы порекомендовал обработать это следующим образом.


Обрабатывать вызов RESTful как объявление функции.

GET /foo
foo()

Для некоторых функций требуются параметры.

GET /foo?start=??&count=??
foo(start, count)

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

При использовании параметров по умолчанию можно предположить, что функция была определена как

foo(start = 0, count = 10)

так что вызов GET /foo будет фактически эквивалентен GET /foo?start=0&count=10, тогда как вызов GET /foo?start=100 будет эквивалентен GET /foo?start=100&count=10.

Если вы не хотите использовать параметры по умолчанию, вы можете заставить пользователя API явно установить start и count:

foo(start, count)

, чтобы при вызове GET /foo возвращался код состояния 400 Bad Request, а при вызове GET /foo?start=0&count=10 возвращался код состояния 200 OK вместе с содержимым, содержащимся в указанном диапазоне.

В любом случае вам придется решить, как вы будете обрабатывать ошибки, например

GET /foo?start=-10&count=99999999

Если параметры имеют максимумы и минимумы, вам необходимо решить, следует ли нормализовать параметры или просто вернуть ошибки. Предыдущий пример может возвращать код состояния 400 Bad Request, но он также может быть ограничен:

GET /foo?start=0&count=1000

В конце концов, вам решать, что имеет смысл в контексте вашей заявки.

0 голосов
/ 10 февраля 2012

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

В других случаях я бы согласился, что неявное управление было бы плохой идеей, поскольку потребитель хотел бы иметь возможность правильно предсказать ответ, а также может потребоваться простая спецификация. В таких случаях 405, 400 и 303.

Это вопрос контекста.

...