Использование метода PUT с неполными представлениями

Каково стандартное поведение, ожидаемое от PUT с неполным представлением ресурса?

Например, у меня есть User в /api/users/1, который представлен HAL json ниже:

{'id': 1,
 'username': 'joedoe',
 'email': '[email protected]',
 'password_hash': '9039dmk38f84uf4029i339kf32f0932i',
 'last_visit': '2013-11-04 21:09:01',
 'public': true,
 '_links': {'self': {'href': 'http://foo.bar.com/api/users/1'}}

}

Затем я делаю запрос PUT для изменения username и email, а в представлении отсутствуют другие атрибуты:

PUT /api/users/1

{'username': 'joeydoey',
 'email': '[email protected]'}

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

Я не могу найти что-либо, что я мог бы связать с этим по стандарту HTTP, поэтому я должен спросить, что ожидаемое стандартизованное поведение в этом случае?

  • Это должно привести к ошибке, поскольку это подразумевает частичное обновление. Схема полезной нагрузки PUT должна быть идентична схеме, полученной с помощью GET, с тем же ресурсом и типом носителя.

  • Это должно быть успешным, потому что сервер может заполнить пробелы по умолчанию для этого типа носителя. В этом случае он будет reset пароль пустым или стандартным паролем и соответствующим образом обновит хеш, и установите значения last_visit и public values ​​в значения по умолчанию. Этот параметр имеет гораздо больший смысл, если вы рассматриваете HATEOAS, если клиент отправляет тот же тип носителя, который возвращается сервером, поскольку он не может предсказать, как будут изменяться элементы управления гипермедиа, представление обязательно является неполным каждый раз, когда клиент не является 't отправка всех гиперссылок, и сервер должен reset их соответственно.

  • И 1 и 2 действительны, потому что нет стандартизованного поведения, и это зависит от типа носителя, чтобы решить, что с ним делать. Это не так, потому что PUT не подчиняется самому ресурсу, а заменяет его.

Имейте в виду, что я не спрашиваю, что правильно или что имеет смысл. Я спрашиваю, какой из них поддерживается стандартами.

Ответ 1

Пока результат PUT является полной заменой от понимания клиентом ресурса (т.е. предыдущие значения для тех свойств, которые не были переданы, не влияют на их значение после PUT), он должен преуспеть. Тем не менее, это немного сбивает с толку, так как многие люди склонны равнозначно использовать это использование PUT с семантикой обновления на уровне поля (а не полной заменой).

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

Однако ваш пример ссылок не относится к тому, чтобы не передавать значения по умолчанию, поэтому это не хороший пример "неполного представления". Скорее, ссылки не являются частью клиентского представления ресурса на сервере. Я думаю, что вы добавили еще одну концепцию в микс: свойства, которые возвращаются только с сервера клиенту. Это то, о чем я говорил в другой теме, которая вызвала этот пост.

То, о чем я говорю, не является неполным представлением; это другое представление. Вы действительно имеете дело с двумя разными типами носителей (т.е. Представлениями), описывающими один и тот же ресурс. Один происходит от клиента (мы будем называть его application/vnd.example.api.client), а другой - с сервера (application/vnd.example.api.server). Они не могут быть явно помечены как таковые, но это, по крайней мере, неявно, что происходит. Поэтому, поскольку они представляют собой два разных типа медиа, они выражают разные вещи о том же ресурсе.

Поскольку вы упомянули HAL, считайте, что клиент обычно не отправляет сообщение на сервер приложения типа носителя /hal + json. Посмотрите на подтверждение от HALTalk для примера. Ожидаемый тип содержимого - application/json, а не application/hal + json. И, если вы посмотрите на примерный пост, в нем ничего нет HAL-ish. Нет ссылок, нет внедренных объектов и т.д. Но... если вы затем получите URL-адрес, возвращенный из заголовка Location, возвращенного из этого POST, он будет, полагая, что ваш клиент принимает HAL через JSON, возвращает ответ типа application/hal + json (т.е. пользователь со ссылками). Два разных типа медиа, два разных представления одного и того же ресурса.

Итак, позвольте мне украсить ваш пример заголовками Accept и Content-Type, чтобы проиллюстрировать мою точку.

Запрос

PUT /api/users/1 HTTP/1.1
Content-Type: application/vnd.example.api.client+json

{'username': 'joeydoey',
 'email': '[email protected]'}

ответ

200 OK
Content-Type: application/hal+json;profile=application/vnd.example.api.server

{'id': 1,
 'username': 'joeydoey',
 'email': '[email protected]',
 'password_hash': '9039dmk38f84uf4029i339kf32f0932i',
 '_links': {'self': {'href': 'http://foo.bar.com/api/users/1'}}
}

Большинство систем не обращаются к этому количеству деталей, чтобы описать их типы носителей. Обычно он просто обрамлен более общим типом (например, application/json или только один пользовательский тип носителя). Однако ничто из этого не меняет тот факт, что, хотя он является одним и тем же базовым ресурсом, это два разных представления. Есть смысл?

Ответ 2

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

В вашем примере хеш-пароль не похоже на то, что сервер может заполнить, не так ли? В этом случае PUT должен привести к ошибке.