должен ли я использовать метод PUT для обновления, если я также обновляю атрибут timestamp

Если быть более точным:

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

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

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

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

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

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

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

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

saludos

sas

4 ответов


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

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

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

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

исходный сервер должен отклонить любой PUT запрос, содержащий Content-поле заголовка диапазона, так как оно может быть истолковано как частичный содержимое (или может быть частичным содержимым это ошибочно ставится как полное представление.) Частичное содержимое обновления возможны для отдельно определенный ресурс с состояние, перекрывающее часть из больший ресурс, или с помощью другой метод, который был в частности, определенный для частичной обновления (например, патч метод, определенный в [RFC5789]).

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


As 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>

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

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), мы в порядке, и наше решение совершенно спокойно. Если, однако, клиенты нуждаются в доступе к этим данным, самым чистым подходом было бы использование 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>

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

обратите внимание:
Я согласен с Даррел Миллер ' s возьмите на себя вопрос, но я хотел бы представить другой подход сверху. Обратите внимание, что этот подход не подкреплен никакими стандартами/RFCs/etc, это просто другой подход к проблеме.


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

Так:

Put = UPDATE

Post = вставить

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


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

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

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