я должен использовать метод PUT для обновления, если я также обновляю атрибут timestamp - PullRequest
25 голосов
/ 16 апреля 2011

Чтобы быть более точным:

В соответствии со стилем отдыха, обычно предполагается, что методы POST, GET, PUT и DELETE http должны использоваться для операций CREATE, READ, UPDATE и DELETE (CRUD).

На самом деле, если мы придерживаемся определения методов http, это может быть не так ясно

В этой статье объясняется, что:

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

Главным образом потому, что

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

В моем случае я обычно выпускаю обновления, пропуская все данные ресурса, поэтому я могу использовать PUT для обновлений, но каждый раз, когда я выпускаюОбновление Я сохраняю столбцы LastUser и LastUpdate с идентификатором пользователя, который внес изменение, и временем операции.

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

saludos

sas

Ответы [ 4 ]

23 голосов
/ 16 апреля 2011

Игнорирование комментария о CRUD-отображении стиля REST для методов HTTP, это отличный вопрос.

Ответ на ваш вопрос: да, вы можете свободно использовать PUT в этом сценарии, даже если некоторые элементы ресурса обновляются сервером неидемпотентным образом. К сожалению, причина ответа довольно расплывчата. Важно понять, что было целью запроса клиента. Клиент намеревался полностью заменить содержимое ресурса переданными значениями. Клиент не несет ответственности за то, что сервер выполняет другие операции, и поэтому семантика метода HTTP не нарушается.

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

Полный, полный и частичный дебаты о ресурсах, наконец, изложены в обновлении спецификации HTTP

Исходный сервер ДОЛЖЕН отклонить любой PUT запрос, который содержит Поле заголовка Content-Range, так как оно может быть неправильно истолковано как частичное содержание (или может быть частичным содержанием что по ошибке ставится как полное представление). Частичное содержание обновления возможны, ориентируясь на отдельно идентифицированный ресурс с состояние, которое перекрывает часть больший ресурс, или с помощью другой метод, который был специально определено для частичного обновления (например, PATCH метод, определенный в [RFC5789]).

Итак, то, что мы должны делать, теперь ясно. Что не так ясно, так это то, почему существует такое ограничение, что только разрешено отправлять полные ответы Этот вопрос был задан, и ИМХО остается без ответа в этой теме на rest-обсуждение.

7 голосов
/ 16 апреля 2011

Поскольку LastUser и LastUpdate не могут быть изменены клиентом, я бы полностью удалил их из представления вашего ресурса.Позвольте мне объяснить мои рассуждения на примере.

Предположим, что наш типичный пример API вернет клиенту следующее представление при запросе на предоставление одного ресурса:

GET /example/123

<?xml version="1.0" encoding="UTF-8" ?>
<example>
    <id>123</id>
    <lorem>ipsum</lorem>
    <dolor>sit amet</dolor>
    <lastUser uri="/user/321">321</lastUser>
    <lastUpdate>2011-04-16 20:00:00 GMT</lastUpdate>
</example>

Если клиентхочет изменить ресурс, он предположительно возьмет все представление и отправит его обратно в API.

PUT /example/123

<?xml version="1.0" encoding="UTF-8" ?>
<example>
    <id>123</id>
    <lorem>foobar</lorem>
    <dolor>foobaz</dolor>
    <lastUser>322</lastUser>
    <lastUpdate>2011-04-16 20:46:15 GMT+2</lastUpdate>
</example>

Поскольку API генерирует значения для lastUser и lastUpdate автоматическии не может принять данные, предоставленные клиентом, наиболее подходящим ответом будет 400 Bad Request или 403 Forbidden (поскольку клиент не может изменить эти значения).

Если мы хотим быть совместимыми с REST и отправить полноепредставление ресурса при выполнении запроса PUT, нам нужно удалить lastUser и lastUpdate из представления ресурса.Это позволит клиентам отправлять полную сущность через PUT:

PUT /example/123

<?xml version="1.0" encoding="UTF-8" ?>
<example>
    <id>123</id>
    <lorem>foobar</lorem>
    <dolor>foobaz</dolor>
</example>

Сервер будет принимать полное представление теперь, когда он не содержит lastUpdate и lastUser.

.Остается вопрос, как предоставить клиентам доступ к lastUpdate и lastUser.Если им это не нужно (а эти поля требуются только внутренне API), мы в порядке, и наше решение идеально подходит для RESTful.Однако, если клиентам нужен доступ к этим данным, самым чистым подходом будет использование заголовков HTTP:

GET /example/123

...
Last-Modified: Sat, 16 Apr 2011 18:46:15 GMT
X-Last-User: /user/322
...

<?xml version="1.0" encoding="UTF-8" ?>
<example>
    <id>123</id>
    <lorem>foobar</lorem>
    <dolor>foobaz</dolor>
</example>

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

GET /example/123

...
Last-Modified: Sat, 16 Apr 2011 18:46:15 GMT
...

<?xml version="1.0" encoding="UTF-8" ?>
<example last-update="2011-04-16 18:46:15 GMT" last-user="/user/322">
    <id>123</id>
    <lorem>foobar</lorem>
    <dolor>foobaz</dolor>
</example>

Таким образом, мы по крайней мере избежим проблемы, когдаклиент попытается отправить все узлы XML в последующем запросе PUT.Это не будет работать с JSON, и решение все еще немного на грани идемпотентности (поскольку API все равно придется игнорировать атрибуты XML при обработке запроса).

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

GET /example/123

<?xml version="1.0" encoding="UTF-8" ?>
<example>
    <id>123</id>
    <lorem>foobar</lorem>
    <dolor>foobaz</dolor>
    <lastUpdateUri>/example/123/last-update</lastUpdateUri>
</example>

... а затем:

GET /example/123/last-update

<?xml version="1.0" encoding="UTF-8" ?>
<lastUpdate>
    <resourceUri>/example/123</resourceUri>
    <updatedBy uri="/user/321">321</updatedBy>
    <updatedAt>2011-04-16 20:00:00 GMT</updatedAt>
</lastUpdate>

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

Обратите внимание:
Я согласен с Даррел Миллер по вопросу , но я хотел предложить другой подход сверхуэтогоОбратите внимание, что этот подход не подкреплен никакими стандартами / RFC / и т. Д., Это просто другой подход к проблеме.

4 голосов
/ 16 апреля 2011

Недостатком использования PUT для создания ресурсов является то, что клиент должен предоставить уникальный идентификатор, представляющий объект, который он создает.Хотя обычно клиент может сгенерировать этот уникальный идентификатор, большинство разработчиков приложений предпочитают, чтобы его серверы (обычно через свои базы данных) создавали этот идентификатор.В большинстве случаев мы хотим, чтобы наш сервер контролировал генерацию идентификаторов ресурсов.Так что же нам делать?Мы можем переключиться на использование POST вместо PUT.

Итак:

Put = ОБНОВЛЕНИЕ

Post = INSERT

Надеюсь, это поможет в вашем конкретном случае.

0 голосов
/ 09 сентября 2016

Методы HTTP POST и PUT не являются HTTP-эквивалентом создания и обновления CRUD. Они оба служат разным целям. Вполне возможно, допустимо и даже в некоторых случаях предпочтительнее использовать PUT для создания ресурсов или POST для обновления ресурсов.

Используйте PUT, когда вы можете полностью обновить ресурс через определенный ресурс. Например, если вы знаете, что статья находится на http://example.org/article/1234,, вы можете поместить новое представление ресурса этой статьи непосредственно через PUT на этот URL.

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

...