должен ли я использовать метод 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 style mapping CRUD к методам HTTP, это отличный вопрос.
Ответ на ваш вопрос: Да, вы можете использовать PUT в этом сценарии, даже если есть некоторые элементы ресурса, которые обновляются сервером неидемпотентным образом. К сожалению, рассуждения, стоящие за ответом, довольно расплывчаты. Самое главное, это понять, что было целью запроса клиента. Клиент намеревался полностью замените содержимое ресурса переданными значениями. Клиент не несет ответственности за выполнение сервером других операций, и поэтому семантика метода HTTP не нарушается.
Это рассуждение используется для того, чтобы позволить серверу обновлять счетчик страниц при выполнении операции GET. Клиент не запрашивал обновления, поэтому GET безопасен, даже если сервер решил сделать обновление.
Дискуссия о целом, полном ресурсе против частичного ресурса имеет наконец-то было прописано в обновлении к http spec
Итак, теперь ясно, что мы должны делать. Что не совсем ясно, так это почему существует это ограничение только на то, чтобы иметь возможность отправлять полные ответы. Этот вопрос был задан, и ИМХО остается без ответа в этой теме на отдыхе-обсуждение.Исходный сервер должен отклонить любое PUT запрос, содержащий Content-поле заголовка диапазона, так как оно может быть неправильно истолковано как частичное содержание (или может быть частичным содержанием это ошибочно ставится как полное представление). Частичное содержание обновления возможны с помощью таргетинга a отдельно выделенный ресурс с состояние, которое перекрывает часть больший ресурс, или путем с помощью другой метод, который был специально определено для частичного обновления (например, патч метод, определенный в [RFC5789]).
Поскольку
Предположим, что наш типичный пример API вернет клиенту следующее представление, когда его попросят предоставить один ресурс:LastUser
иLastUpdate
не могут быть изменены клиентом, я бы удалил их из представления вашего ресурса вообще. Позвольте мне объяснить свои рассуждения на примере.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>
lastUser
иlastUpdate
автоматически и не может принимать данные, предоставленные клиентом, наиболее подходящим ответом будет400 Bad Request
или403 Forbidden
(поскольку клиент не может изменять эти значения). Если мы хотим быть совместимыми с REST и отправлять полное представление ресурса при выполнении запроса PUT, нам нужно удалитьlastUser
иlastUpdate
из представления ресурса. Это позволит клиентам отправлять полную сущность через Поставить: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>
(вышесказанное можно также красиво расширить, чтобы обеспечить полный журнал аудита с отдельными изменениями, при условии, что доступен журнал изменений ресурсов.)
Пожалуйста, обратите внимание:
Я согласен сДаррелом Миллером взять на себя этот вопрос , но я хотел бы предложить другой подход к этому вопросу. Обратите внимание, что этот подход не подкреплен никакими стандартами / RFC / etc, это просто другой взгляд на проблема.
Недостаток использования PUT для создания ресурсовсостоит в том, что клиент должен предоставить уникальный идентификатор, представляющий объект, который он создает. В то время как клиент обычно может генерировать этот уникальный идентификатор, большинство разработчиков приложений предпочитают, чтобы их серверы (обычно через свои базы данных) создавали этот идентификатор. В большинстве случаев мы хотим, чтобы наш сервер контролировал генерацию идентификаторов ресурсов. Так что же нам делать? Мы можем переключиться на использование POST вместо PUT.
Итак:
Положить = Обновить
Post = вставить
Надеюсь, это поможет в вашем конкретном случае.
HTTP-методы POST и PUT не являются HTTP-эквивалентом create и update CRUD. Они оба служат разным целям. Вполне возможно, допустимо и даже предпочтительно в некоторых случаях использовать PUT для создания ресурсов или использовать POST для обновления ресурсов.
Используйте PUT, когда вы можете полностью обновить ресурс через определенный ресурс. Например, если вы знаете, что статья находится в http://example.org/article/1234 , Вы можете поместить новое представление ресурса эту статью прямо через сайт выложили по этому адресу.
Если вы не знаете фактического местоположения ресурса, например, когда вы добавляете новую статью, но не имеете ни малейшего представления, где ее хранить, Вы можете разместить ее на URL-адрес, и пусть сервер решает фактический URL-адрес.