Поскольку 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 / и т. Д., Это просто другой подход к проблеме.