Предположим, что REST API в ответ на HTTP- GET
запрос возвращает некоторые дополнительные данные в подобъекте owner
:
{
id: 'xyz',
... some other data ...
owner: {
name: 'Jo Bloggs',
role: 'Programmer'
}
}
Понятно, что мы не хотим, чтобы кто-то мог PUT
вернуться
{
id: 'xyz',
... some other data ...
owner: {
name: 'Jo Bloggs',
role: 'CEO'
}
}
и добиться этого. Действительно, в этом случае мы, вероятно, даже не собираемся реализовывать способ, позволяющий этому добиться успеха.
Но этот вопрос касается не только подобъектов: что вообще следует делать с данными, которые нельзя изменять в запросе PUT?
Должно ли оно быть пропущено в запросе PUT?
Должно ли это быть тихо отброшено?
Должен ли он быть проверен, и если он отличается от старого значения этого атрибута, вернуть в ответ код ошибки HTTP?
Или мы должны использовать патчи RFC 6902 JSON вместо отправки всего JSON?
rest
http
http-request
Робин Грин
источник
источник
Ответы:
Нет ни правила, ни в спецификации W3C, ни в неофициальных правилах REST, которые утверждают, что
PUT
необходимо использовать ту же схему / модель, что и соответствующая ейGET
.Приятно, если они похожи , но нет ничего необычного в том,
PUT
чтобы делать вещи немного по-другому. Например, я видел много API-интерфейсов, которые включают в себя некоторый идентификатор в контенте, возвращаемом символом aGET
, для удобства. Но сPUT
, этот идентификатор определяется исключительно URI и не имеет значения в контенте. Любой идентификатор, найденный в теле, будет игнорироваться.REST и сеть в целом тесно связаны с принципом надежности : «Будьте консервативны в том, что вы делаете [отправляйте], будьте либеральными в том, что вы принимаете». Если вы философски согласны с этим, то решение очевидно: игнорируйте любые неверные данные в
PUT
запросах. Это относится как к неизменным данным, как в вашем примере, так и к действительной бессмыслице, например, к неизвестным полям.PATCH
это потенциально другой вариант, но вы не должны реализовывать,PATCH
если вы не собираетесь поддерживать частичные обновления.PATCH
означает обновление только определенных атрибутов, которые я включаю в контент ; это не означает замену всей сущности, но исключает некоторые конкретные поля . То, о чем вы на самом деле говорите, это не частичное обновление, это полное обновление, идемпотент и все такое, просто эта часть ресурса доступна только для чтения.Хорошо, если вы выберете эту опцию, то отправите обратно 200 (ОК) с действительным обновленным объектом в ответе, чтобы клиенты могли четко видеть, что поля только для чтения не были обновлены.
Есть, конечно, некоторые люди, которые думают иначе - попытка обновить доступную только для чтения часть ресурса должна быть ошибкой. Для этого есть некоторые основания, прежде всего на том основании, что вы обязательно вернете ошибку, если весь ресурс доступен только для чтения и пользователь попытается его обновить. Это определенно идет вразрез с принципом надежности, но вы можете считать его более «самодокументированным» для пользователей вашего API.
Для этого есть два соглашения, каждое из которых соответствует вашим оригинальным идеям, но я остановлюсь на них. Во-первых, нужно запретить отображение в содержимом доступных только для чтения полей и вернуть HTTP 400 (неверный запрос), если они это делают. API такого рода также должны возвращать HTTP 400, если есть какие-либо другие нераспознанные / неиспользуемые поля. Второе - требовать, чтобы доступные только для чтения поля были идентичны текущему контенту, и возвращать 409 (Конфликт), если значения не совпадают.
Мне действительно не нравится проверка на равенство с 409, потому что она неизменно требует, чтобы клиент сделал a
GET
, чтобы получить текущие данные, прежде чем он сможет сделать aPUT
. Это просто нехорошо и, вероятно, приведет к снижению производительности, для кого-то, где-нибудь. Мне также действительно не нравится 403 (Запрещено) для этого, поскольку это означает, что защищен весь ресурс, а не только его часть. Поэтому я считаю, что если вам абсолютно необходимо выполнить проверку вместо того, чтобы следовать принципу надежности, проверьте все ваши запросы и верните 400 для всех, которые имеют дополнительные или недоступные для записи поля.Убедитесь, что ваш 400/409 / что-либо включает в себя информацию о том, что конкретная проблема и как ее исправить.
Оба эти подхода верны, но я предпочитаю первый в соответствии с принципом надежности. Если вам когда-либо приходилось работать с большим API REST, вы по достоинству оцените ценность обратной совместимости. Если вы когда-нибудь решите удалить существующее поле или сделать его доступным только для чтения, это будет обратно совместимым изменением, если сервер просто игнорирует эти поля, а старые клиенты все равно будут работать. Однако, если вы выполните строгую проверку содержимого, оно больше не будет обратно совместимым, и старые клиенты перестанут работать. Первый, как правило, означает меньше работы как для сопровождающего API, так и для его клиентов.
источник
То же самое
Следуя RFC, PUT должен будет доставить полный объект к ресурсу. Основная причина этого заключается в том, что PUT должен быть идемпотентом. Это означает, что запрос, который повторяется, должен приводить к тому же результату на сервере.
Если вы разрешаете частичное обновление, оно не может быть более эффективным. Если у вас есть два клиента. Клиент A и B, затем может развиваться следующий сценарий:
Клиент А получает картинку из ресурсов изображений. Это содержит описание изображения, которое все еще действует. Клиент B помещает новое изображение и обновляет описание соответствующим образом. Картина изменилась. Клиент А видит, ему не нужно менять описание, потому что это так, как он хочет, и ставить только изображение.
Это приведет к несогласованности, к изображению прикреплены неверные метаданные!
Еще более раздражает то, что любой посредник может повторить запрос. В случае, если он решит, что PUT не удалось.
Значение PUT не может быть изменено (хотя вы можете использовать его неправильно).
Другие опции
К счастью, есть еще один вариант, это патч. PATCH - это метод, который позволяет вам частично обновить структуру. Вы можете просто отправить частичную структуру. Для простых приложений это нормально. Этот метод не гарантирован, чтобы быть тем же самым. Клиент должен отправить запрос в следующей форме:
И сервер может ответить обратно с 204 (без содержимого), чтобы отметить успех. При ошибке вы не можете обновить часть структуры. Метод PATCH является атомарным.
Недостаток этого метода заключается в том, что не все браузеры поддерживают это, но это наиболее естественный вариант в REST-сервисе.
Пример запроса исправления: http://tools.ietf.org/html/rfc5789#section-2.1
Json патчинг
Опция json кажется довольно всеобъемлющей и интересной. Но это может быть трудно осуществить для третьих лиц. Вы должны решить, сможет ли ваша пользовательская база справиться с этим.
Это также несколько запутанно, потому что вам нужно создать небольшой интерпретатор, который преобразует команды в частичную структуру, которую вы собираетесь использовать для обновления вашей модели. Этот интерпретатор также должен проверить, имеют ли предоставленные команды смысл. Некоторые команды отменяют друг друга. (напишите fielda, удалите fielda). Я думаю, что вы хотите сообщить об этом клиенту, чтобы ограничить время отладки на его / ее стороне.
Но если у вас есть время, это действительно элегантное решение. Вы все еще должны проверить поля, конечно. Вы можете комбинировать это с методом PATCH, чтобы остаться в модели REST. Но я думаю, что POST будет приемлемым для здесь.
Плохо
Если вы решили пойти с опцией PUT, что несколько рискованно. Тогда вам следует хотя бы не сбрасывать ошибку. У пользователя есть определенное ожидание (данные будут обновлены), и если вы нарушите это, вы дадите некоторое время разработчикам.
Вы можете выбрать для возврата: 409 Конфликт или 403 Запрещено. Это зависит от того, как вы смотрите на процесс обновления. Если вы видите это как набор правил (ориентированных на систему), тогда конфликт будет лучше. Как-то так, эти поля не обновляются. (Противоречит правилам). Если вы видите это как проблему авторизации (ориентированную на пользователя), вы должны вернуть запрещенный. С: вы не авторизованы для изменения этих полей.
Вы все еще должны заставить пользователей отправлять все изменяемые поля.
Разумный вариант для обеспечения этого - установить для него подресурс, который предлагает только изменяемые данные.
Личное мнение
Лично я бы пошел (если вам не нужно работать с браузерами) для простой модели PATCH, а затем позже расширил бы ее с помощью процессора исправлений JSON. Это может быть сделано путем дифференцирования по mimetypes: mime-тип json patch:
применение / JSON-патч
И JSON: приложение / JSON-патч
позволяет легко реализовать его в два этапа.
источник