нам нужно отправить все данные статьи обратно в API для обновления, и многопользовательская работа не может быть реализована. Например, редактор может отправить данные на 5 секунд старше и исправить перезапись, что некоторые другие журналисты только что сделали 2 секунды назад, и я никак не мог объяснить это клиентам, поскольку те, кто публикует статью, на самом деле никак не связаны с обновлением контента.
Подобные вещи являются проблемой, независимо от того, что вы делаете, это очень похоже на проблему с распределенным управлением исходным кодом (Mercurial, Git и т. Д.), И решение, записанное в HTTP / ReST, выглядит немного похожим.
Предположим, у вас есть два пользователя, Алиса и Боб, оба работают над ними /articles/lunch
. (для ясности ответ выделен жирным шрифтом)
Во-первых, Алиса создает статью.
PUT /articles/lunch HTTP/1.1
Host: example.com
Content-Type: text/plain
Authorization: Basic YWxpY2U6c2VjcmV0
Hey Bob, what do you want for lunch today?
301 Moved Permanently
Location: /articles/lunch/1
Сервер не создал ресурс, потому что к запросу не было прикреплено никакой «версии» (при условии, что /articles/{id}/{version}
для выполнения создания был создан идентификатор . Алиса была перенаправлена на URL-адрес статьи / версии, которую она будет создавать. Пользователь Алисы). Затем агент повторно применяет запрос по новому адресу.
PUT /articles/lunch/1 HTTP/1.1
Host: example.com
Content-Type: text/plain
Authorization: Basic YWxpY2U6c2VjcmV0
Hey Bob, what do you want for lunch today?
201 Created
И теперь статья была создана. Далее Боб смотрит на статью:
GET /articles/lunch HTTP/1.1
Host: example.com
Authorization: Basic Ym9iOnBhc3N3b3Jk
301 Moved Permanently
Location: /articles/lunch/1
Боб смотрит туда:
GET /articles/lunch/1 HTTP/1.1
Host: example.com
Authorization: Basic Ym9iOnBhc3N3b3Jk
200 Ok
Content-Type: text/plain
Hey Bob, what do you want for lunch today?
Он решает добавить свои собственные изменения.
PUT /articles/lunch/1 HTTP/1.1
Host: example.com
Content-Type: text/plain
Authorization: Basic Ym9iOnBhc3N3b3Jk
Hey Bob, what do you want for lunch today?
Does pizza sound good to you, Alice?
301 Moved Permanently
Location: /articles/lunch/2
Как и в случае с Алисой, Боб перенаправлен туда, где он будет создавать новую версию.
PUT /articles/lunch/2 HTTP/1.1
Host: example.com
Content-Type: text/plain
Authorization: Basic Ym9iOnBhc3N3b3Jk
Hey Bob, what do you want for lunch today?
Does pizza sound good to you, Alice?
201 Created
Наконец, Алиса решает, что она хотела бы добавить к своей собственной статье:
PUT /articles/lunch/1 HTTP/1.1
Host: example.com
Content-Type: text/plain
Authorization: Basic YWxpY2U6c2VjcmV0
Hey Bob, what do you want for lunch today?
I was thinking about getting Sushi.
409 Conflict
Location: /articles/lunch/3
Content-Type: text/diff
---/articles/lunch/2
+++/articles/lunch/3
@@ 1,2 1,2 @@
Hey Bob, what do you want for lunch today?
-Does pizza sound good to you, Alice?
+I was thinking about getting Sushi.
Вместо перенаправления в обычном режиме клиенту возвращается другой код состояния 409
, который сообщает Алисе, что версия, из которой она пыталась перейти, уже разветвлена. Новые ресурсы были созданы в любом случае (как показано в Location
заголовке), и различия между ними были включены в тело ответа. Алиса теперь знает, что запрос, который она только что сделала, нужно как-то объединить.
Все это перенаправление связано с семантикой PUT
, которая требует, чтобы новые ресурсы создавались именно там, где запрашивает строка запроса. это также могло бы сохранить цикл запроса, используя POST
вместо этого, но тогда номер версии должен был бы быть закодирован в запросе каким-то другим волшебством, которое мне показалось менее очевидным для целей иллюстрации, но, вероятно, все еще было бы предпочтительным в реальном API минимизировать циклы запроса / ответа.
api/article?action=publish
? Параметры запроса предназначены для тех случаев, когда состояние ресурса зависит от упомянутого вами «алгоритма» (или действия). Напримерapi/articles?sort=asc
, действительный