Как мне создать ресурс упорядоченного списка в спокойном сервисе?

11

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

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

Как мне спроектировать спокойный сервис ресурса упорядоченного списка?

В частности, как я должен спроектировать listи itemмодель спокойного ресурса? Самым распространенным дизайном, который я видел, является itemобъект, имеющий свойство orderили position. Другой подход, который я услышал, - это двусвязный список предметов.

Какой подход не слишком много пишет в базу данных и, как правило, быстро обновляется и читается для клиентов? Как должны быть выставлены конечные точки как?

Рико Калер
источник
Из любопытства, почему важно возвращать заказанный список специально?
Адам Уэллс
Ну, я думаю, я специально не собираюсь возвращать упорядоченный список ресурсов, а просто сохраняю порядок / позицию ресурса, который может быть частью фактического ресурса списка или просто неявно частью списка. Я хочу сказать, чтобы пользователь мог изменить порядок задач в списке задач. Но независимо от того, что есть еще список, где порядок имеет значение. То, что я не могу найти, это хороший способ спроектировать это
Rico Kahler

Ответы:

14

Представление упорядоченного списка является одной из трудных проблем с реляционными базами данных. Добавление свойства position в отношение членства в списке является наиболее распространенным способом сделать это, так как вы можете легко получить упорядоченный список, добавив его ORDER BY positionв запрос SQL, и потому что вы можете легко вставлять элементы в середину списка, усредняя значения предыдущего и последующего члена списка, при условии, что позиция является числом с плавающей точкой, а не целым числом.

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

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

Если у вас есть только несколько сотен элементов в списке, просто передайте весь список в запросе. Предполагая, что мы хотим изменить порядок, [1, 2, 3, 4]где члены списка являются идентификаторами, мы могли бы

POST /url/of/the/list
Content-type: application/json
...

[1, 2, 4, 3]

Затем серверная часть может перевести это на любую используемую вами технологию базы данных, но пользователь API не должен учитывать эти детали.

Если список большой и элементы обычно запрашиваются индивидуально, вы можете разрешить индекс в URL:

GET /page/7

Если вы работаете в HATEOAS, ответ может включать ссылки «предыдущий / следующий», чтобы упростить навигацию, если ресурс обычно используется таким образом. Однако это не обязательно означает, что ваша база данных также содержит этот двусвязный список.

Если список очень большой, вы можете захотеть выставить ArrayListподобные операции, такие как insertили push/ append. Я мог бы представить такой звонок, как

POST /url/of/the/list?at=1357;mode=insert
...

description of the item to insert

Если переупорядочение является распространенным случаем, и переупорядочение должно быть совершено немедленно, тогда вы можете предложить подходящую конечную точку в своем API:

POST /url/of/the/list/reorder-item?from=783;to=1357

Если переупорядоченный список должен быть зафиксирован явно, будет проще перенести новый заказ в виде документа JSON, см. Выше.

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

Амон
источник
1
Обратите внимание, что подход «заменить весь список» может стать проблематичным, если несколько клиентов вносят изменения. Если вы не примете никаких мер предосторожности, вы можете перезаписать чужие изменения («победит последний, кто напишет»).
oefe
Подобные
2

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

Этот подход предложил переместить элемент в порядке:

POST / url / of / the / list / reorder-item? От = 783; до = 1357

Это может зависеть от условий гонки, если у вас нет Сериализуемой транзакции. Уровень READ_COMMITTED по умолчанию в большинстве БД не устраняет условия гонки!

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

Он страдает от последних побед, но это верно буквально для ЛЮБОГО API. Независимо от того, какой API вы реализуете, другой клиент, возможно, обновил объект, пока вы просматриваете страницу.

Чарльз Каппс
источник