Как реализовать надежную нумерацию страниц с помощью RESTful API, когда результирующий набор может измениться? - PullRequest
7 голосов
/ 13 декабря 2011

Я реализую RESTful API, который выставляет Orders как ресурс и поддерживает разбиение на страницы через набор результатов:

GET /orders?start=1&end=30

, где заказы на разбиение на страницы сортируются по ordered_at отметке времени по убыванию.Это в основном подход № 1 из вопроса SO Разбиение на страницы в веб-приложении REST .

Если пользователь запрашивает вторую страницу заказов (GET /orders?start=31&end=60), сервер просто повторно запрашиваеттаблица заказов снова сортируется по ordered_at DESC и возвращает записи в позициях с 31 по 60.

У меня проблема: что произойдет, если результирующий набор изменится (например, будет добавлен новый порядок), пока пользовательпросматриваете записи?В случае добавления нового заказа пользователь увидит старый заказ № 30 в первой позиции на второй странице результатов (потому что тот же заказ теперь № 31).Хуже того, в случае удаления пользователь видит старый порядок # 32 в первой позиции на второй странице (# 31) и вообще не увидит старый порядок # 31 (теперь # 30).

Я не вижу решения этой проблемы, если каким-то образом не сделать сервер RESTful с состоянием (urg) или встроить некоторый интеллект разбиения на страницы для каждого клиента ... Каковы некоторые устоявшиеся методы для решения этой проблемы?

Для полноты: мой бэкэнд реализован в Scala / Spray / Squeryl / Postgres;Я создаю два клиентских интерфейса, один в backbone.js, а другой в Python Django.

Ответы [ 5 ]

5 голосов
/ 13 декабря 2011

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

Первоначальный запрос : GET /orders?count=30 возвращает:

{
  "start"=1039;
  "count"=30;
  ...//data
}

Отпри этом потребитель вычисляет, что он хочет запросить:

Следующие запросы: GET /orders?start=1009&count=30, который затем возвращает:

{
  "start"=1009;
  "count"=30;
  ...//data
}

Вместо необработанных индексов вы также можете вернутьссылка на следующую страницу:

{
  "next"="/orders?start=1009&count=30";
}

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

1 голос
/ 14 декабря 2011

WebSockets может сделать это.Вы можете использовать что-то вроде pusher.com , чтобы отслеживать изменения в вашей базе данных в реальном времени и передавать их клиенту.Затем вы можете связать различные события-толкачи для работы с моделями и коллекциями.

1 голос
/ 13 декабря 2011

При использовании RESTFUL API состояние приложения должно быть на клиенте. Здесь состояние приложения должно указывать временную метку или номер версии, когда вы начинаете просматривать данные. На стороне сервера вам потребуется некоторая форма контрольного журнала, которая представляет собой правильные данные сервера, поскольку она не зависит от того, были ли клиенты и что они сделали. По крайней мере, он должен знать, когда последние данные изменились. Никаких противоречий с REST здесь.

Вы можете добавить параметр версии в ваш get. Когда клиенту сначала требуется страница, он обычно не отправляет версию. Сервер ответов содержит один. Например, если в ответе есть ссылки на следующие / другие страницы, эти ссылки содержат & version = ... Клиент должен отправить версию, когда требуется другая страница.

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

В качестве примера предположим, что вы получили запрос с указанием начала, конца, версии и знаете, что, поскольку версия была обновленной, были удалены три строки, предшествующие началу. Вы можете отправить перенаправление с новой версией start-3, end-3.

1 голос
/ 13 декабря 2011

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

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

  • Плюсы: тот же URL дает те же результаты
  • Минусы: нет очевидного способа получить последние элементы ... Возможно, вы могли бы использовать отрицательные индексы и перенаправить страницу результатов на абсолютные индексы.
0 голосов
/ 27 мая 2016

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

Этот подход пытается использовать переменную left_off для сортировки без использования смещений.

Считайте, что вам нужен результат. Упорядочено по отметке времени order_at DESC.Поэтому, когда я спрашиваю о первом наборе результатов, это

SELECT * FROM Orders ORDER BY order_at DESC LIMIT 25;

верно?Это тот случай, когда вы запрашиваете первую страницу (с точки зрения URL, вероятно, запрос не содержит

yoursomething.com / orders? limit = 25 & left_off = $ timestamp

Затем При получении набора данных просто возьмите метку времени последнего просмотренного элемента. 2015-12-21 13: 00: 49

Теперь для запроса следующие 25 элементов идутto: yoursomething.com / orders? limit = 25 & left_off = 2015-12-21 13: 00: 49 (к последней просмотренной отметке времени)

В Sql вы просто сделаете тот же запрос искажем, где отметка времени равна или меньше $ left_off

SELECT * FROM (SELECT * FROM Orders ORDER BY order_at DESC) as a 
WHERE a.order_at < '2015-12-21 13:00:49' LIMIT 25;

Вы должны получить следующие 25 элементов из последнего увиденного элемента.

Для тех, кто видит этот ответ. Пожалуйста, прокомментируйте, если этот подходактуален или даже возможен в первую очередь. Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...