Разбиение на страницы в веб-приложении REST


это более общая переформулировка этого вопроса (с устранением рельсов конкретных частей)

Я не уверен, как реализовать разбиение на страницы на ресурсе в RESTful веб-приложений. Предполагая, что у меня есть ресурс под названием products, какой из следующих вариантов вы считаете лучшим и почему:

1. Используя только строки запроса

например. http://application/products?page=2&sort_by=date&sort_how=asc
проблема здесь в том, что я не могу использовать полное кэширование страниц, а также URL-адрес не очень чистый и легко запомнить.

2. Использование страниц в качестве ресурсов и строк запроса для сортировки

например. http://application/products/page/2?sort_by=date&sort_how=asc
в этом случае проблема, которая видит, заключается в том, что http://application/products/pages/1 не является уникальным ресурсом с момента использования sort_by=price может дать совершенно другой результат и я все еще не могу использовать кэширование страниц.

3. Использование страниц в качестве ресурсов и сегмента URL для сортировки

например. http://application/products/by-date/page/2
Я лично не вижу никаких проблем в использовании этот метод, но кто-то предупредил меня, что это не очень хороший способ пойти (он не дал причину, так что если вы знаете почему это не рекомендуется, пожалуйста, дайте мне знать)

любой советы, мнения, критика более чем приветствуется. Спасибо.

12 314

12 ответов:

Я думаю, что проблема с версией 3-это скорее проблема "точки зрения" - вы видите страницу как ресурс или продукты на странице.

Если вы видите страницу в качестве ресурса, это совершенно прекрасное решение, так как запрос для страницы 2 всегда будет давать страницу 2.

но если вы видите продукты на странице как ресурс, у вас есть проблема, что продукты на странице 2 могут измениться (старые продукты удалены или что-то еще), в этом случае URI не всегда возвращение одного и того же ресурса(ов).

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

Я согласен с Фионом, но я пойду еще на один шаг и скажу, что для меня страница не ресурс, это свойство запроса. Это заставляет меня выбрать вариант 1 строка запроса только. Это просто кажется правильным. Мне очень нравится, как Twitter API структурировано спокойно. Не слишком простой, не слишком сложный, хорошо документированы. К лучшему или худшему, это мой "переход к" дизайну, когда я нахожусь на заборе, делая что-то так или иначе.

HTTP имеет большой диапазон заголовка, который подходит для разбиения на страницы тоже. Вы можете отправить

Range: pages=1

иметь только первую страницу. Это может заставить вас переосмыслить, что такое страница. Может быть, клиент хочет другой ассортимент товаров. Заголовок диапазона также работает для объявления заказа:

Range: products-by-date=2009_03_27-

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

Range: products-by-date=0-2009_11_30

чтобы получить все продукты старше этой даты. '0', вероятно, не лучшее решение, но RFC, кажется, хочет что-то для диапазона начать. Там могут быть развернуты Парсеры HTTP, которые не будут анализировать units=-range_end.

Если заголовки не являются (приемлемым) вариантом, я считаю, что первое решение (все в строке запроса) - это способ работы со страницами. Но, пожалуйста, нормализуйте строки запроса (сортируйте пары (ключ=значение) в алфавитном порядке). Это решает "?a=1&b=x "и"?b=x&a=1 " задача дифференцирования.

Вариант 1 кажется лучшим, поскольку ваше приложение рассматривает разбиение на страницы как метод для создания другого представления того же ресурса.

сказав это, схема URL относительно незначительна. Если вы разрабатываете свое приложение, чтобы быть гипертекст-управляемый (как и все остальные приложения должны быть по определению), то ваш клиент не будет создавать какие-либо URI самостоятельно. Вместо этого ваше приложение будет давать ссылки на клиент и клиент будут следовать за ними.

один из видов ссылки, которую может предоставить ваш клиент, - это ссылка на разбиение на страницы.

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

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

Я не нахожу url трудно запомнить или нечистым. Для меня это прекрасное использование параметров запроса. Ресурс явно представляет собой список продуктов, а параметры запроса просто говорят, как вы хотите, чтобы список отображался - сортировался и какая страница.

странно, что никто не отметил, что Вариант 3 имеет параметры в определенном порядке. адресу http//применение/продукции/дата/по убыванию/наименование/по возрастанию/Страница/2 и адресу http//применение/продукции/название/по возрастанию/дата/по убыванию/Страница/2

указывают на один и тот же ресурс, но имеют совершенно разные URL-адреса.

для меня Вариант 1 кажется наиболее приемлемым, так как он четко разделяет "что я хочу" и "Как Я хочу" это (он даже имеет знак вопроса между ними lol). Полностраничное кэширование может быть реализовано с использованием полного URL (все параметры будут страдать от одной и той же проблемы в любом случае).

с параметром-в-URL подход единственным преимуществом является чистый URL. Хотя вы должны придумать какой-то способ кодировать параметры и без потерь декодировать их. Конечно, вы можете пойти с URLencode / decode, но это снова сделает URL-адреса уродливыми :)

Я бы предпочел использовать параметры запроса offset и limit.

смещение: для индекса элемента в коллекции.

ограничения: для количество предметов.

клиент может просто продолжать обновлять смещение следующим образом

offset = offset + limit

на следующей странице.

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

Я использую metamug. У них это настраивается. разбиение на страницы при выборе запроса metamug

В настоящее время я использую схему, похожую на эту в моем ASP.NET MVC приложения:

например http://application/products/by-date/page/2

в частности это : http://application/products/Date/Ascending/3

однако я не очень доволен включением подкачки и сортировки информации в маршрут таким образом.

список элементов (продуктов в этом случае) является изменяемым. т. е. в следующий раз, когда кто-то возвращается к url-адресу, который включает параметры подкачки и сортировки, результаты, которые они получают, могут измениться. Так что идея http://application/products/Date/Ascending/3 как уникальный url, который указывает на определенный, неизменный набор продуктов теряется.

В поисках лучших практик я наткнулся на этот сайт:

http://www.restapitutorial.com

на странице ресурсов есть ссылка для загрузки a .pdf, который содержит полные рекомендации REST, предложенные автором. В которой, среди прочего, есть раздел о пагинации.

автор предлагает добавить поддержку как с помощью заголовка Range и с помощью строки запроса параметры.

запрос

пример заголовка HTTP:

Range: items=0-24

пример параметров строки запроса:

GET http://api.example.com/resources?offset=0&limit=25

здесь смещение является начальным номером элемента и ограничения максимальное число возвращаемых элементов.

ответ

ответ должен включать заголовок диапазона содержимого, указывающий, сколько элементов возвращается и сколько всего элементов существует еще предстоит извлечь

примеры заголовков HTTP:

Content-Range: items 0-24/66

Content-Range: items 40-65/*

в рамках .pdf есть и другие предложения для более конкретных случаев.

Я склонен согласиться с slf, что" страница " на самом деле не является ресурсом. С другой стороны, Вариант 3 чище, легче читается и может быть более легко угадан пользователем и даже напечатан при необходимости. Я разрываюсь между вариантами 1 и 3, но не вижу причин не использовать Вариант 3.

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

Я использовал решение 3 Раньше (я пишу много приложений django). И я не думаю, что в этом есть что-то плохое. Он так же генерируется, как и два других (если вам нужно сделать какую-то массовую очистку или тому подобное), и он выглядит чище. Кроме того, ваши пользователи могут угадывать URL-адреса (если это общедоступное приложение), и людям нравится быть в состоянии идти прямо туда, куда они хотят, и угадывание url-адресов чувствует себя расширяющим возможности.

Я использую в своих проектах следующие url:

http://application/products?page=2&sort=+field1-field2

что означает - "дайте мне вторую страницу, упорядоченную по возрастанию по полю 1, а затем по убыванию по полю 2". Или если мне нужно еще больше гибкости, я использую:

http://application/products?skip=20&limit=20&sort=+field1-field2