Представьте себе веб-приложение, хранящее некоторый ресурс данных с некоторым идентификатором, который хранит три вложения (например, pdf) в каждой базе данных.
Схема URL имеет вид
data/{id}/attachment1
data/{id}/attachment2
data/{id}/attachment3
Для вложений существует RESTful API, предоставляющий операции GET/PUT/DELETE, реализующие CRUD-операции на стороне сервера.
Пусть id будет 123, я хотел бы выполнить операцию, в которой
GET
file/123/attachment1
возвращает новое вложение)GET file/123/attachment2
возвращает 404)Обновление должно быть атомарным - полное обновление выполняется сервером или вообще ничего.
Применение простого PUT file/123/attachment1
и DELETE file/123/attachment2
не является атомарным, так как клиент может упасть после PUT, а у сервера нет подсказки, что он должен сделать откат в этом случае.
Так как же мне реализовать эту операцию RESTful способом?
Я придумал два решения, но оба они не кажутся на 100% RESTful:
Хотя это обеспечивает атомарность, я сомневаюсь, что это RESTful, поскольку я перегружаю метод PATCH, используя разные списки параметров, что нарушает ограничение единообразия интерфейса.
DELETE transaction/data/123/attachment2
) и сообщить
о фиксации этой версии ресурса на сервер через PUT на
transaction/data/123. Это обеспечивает атомарность, в то время как
реализовать дополнительную логику на стороне сервера, чтобы справиться с несколькими клиентами
изменяющих один и тот же ресурс, а также с клиентами, которые так и не выполнили фиксацию. Хотя это кажется совместимым с REST, это, по-видимому, нарушает ограничение на отсутствие статичности. Состояние транзакционного ресурса - это не состояние сервиса, а состояние приложения, поскольку каждый транзакционный ресурс связан с одним клиентом.
Я немного застрял здесь, так что любые идеи будут полезны, спасибо!
Вы хотите использовать второй вариант, вариант транзакции.
Вам не хватает создания транзакции:
POST /transaction
HTTP/1.1 301 Moved Permanently
Location: /transaction/1234
Теперь у вас есть ресурс транзакции, который является гражданином первого класса. Вы можете добавить к нему, удалить из него, запросить его текущее содержимое, а затем, наконец, зафиксировать его или удалить (т.е. откатить) транзакцию.
Пока транзакция в процессе, это просто еще один ресурс. Здесь нет состояния клиента. Любой может добавить к этой транзакции.
Когда все готово, сервер применяет изменения сразу, используя какой-то внутренний механизм транзакций, который здесь выходит за рамки.
Вы можете захватывать такие вещи, как Etags и if-Modified заголовки, в под действиях транзакции, чтобы, когда они все применены, вы знали, что что-то не изменилось за вашей спиной.
Предполагая, что ваши URI являются иерархическими:
PUT data/{id}
[attachment2,attachment3]
Часть вашей проблемы заключается в том, что attachment 1/2/3 является ужасным идентификатором. Индекс никогда не должен быть частью ваших URI.