REST API: параметры в адресе и в теле запроса
От: Shmj Ниоткуда  
Дата: 19.09.22 05:38
Оценка:
Как вы решаете когда параметр поместить в адрес а когда в тело запроса?

Вот такая цитата:

Например, если мы создаем REST API для обновления сведений об ученике с помощью PUT (метод HTTP), тогда URI запроса будет {server_host}/students/{student_id}а тело запроса будет таким:

{
  "id": student_id,
  "name": "student name",
  "school_name": "school name"
}


Я много раз видел, как разработчики путаются в том, почему нам нужно отправлять один и тот же параметр в несколько мест. Например, в приведенном выше примере мы отправляем student_id к параметру пути, а также к телу запроса. Может показаться, что мы отправляем повторяющуюся информацию через API, но помните, что параметры тела запроса и пути имеют разные значения и должны использоваться для той цели, которой они будут служить.

Ниже объясняется, почему мы не можем удалить student_id из параметров пути и тела запроса.

Тело запроса используется для отправки и получения данных через REST API. Если мы используем POST/PUT API, то на основе контракта REST API мы должны отправлять всю информацию о ресурсе, потому что эти методы работают со всем ресурсом. В приведенном выше примере student_id также является частью этого ресурса, поэтому он должен присутствовать в теле запроса, иначе тело запроса сможет представлять всю информацию о ресурсе.

После удаления student_id из тела запроса у нас будет следующее тело запроса.

{
  "name": "student name",
  "school_name": "school name"
}


Представляет ли это тело запроса всю информацию о ресурсах? Нет. Так что это нарушение контракта REST.

Итак, чтобы представить состояние ресурса, нам нужно отправить student_id в теле запроса, а чтобы однозначно идентифицировать ресурс, нам нужно отправить student_id в параметре пути.


Т.е. предлагается передавать и в адресе и в теле в данном случае. И вопрос такой — а если в адресе один ID а в теле другой — какую ошибку вернуть? И как это вообще трактовать?
Re: REST API: параметры в адресе и в теле запроса
От: Sinclair Россия http://corp.ingrammicro.com/Solutions/Cloud.aspx
Дата: 19.09.22 05:55
Оценка: 5 (1) +1
Здравствуйте, Shmj, Вы писали:

S>Как вы решаете когда параметр поместить в адрес а когда в тело запроса?

Параметры помещаются в путь тогда, когда они помогают найти объект. Вопрос о том, как устроена навигация, отдаётся на откуп архитектору.
Нужно будет искать студентов по фамилии — можно сделать /students/lastname/ivanov, возвращающий коллекцию студентов.
Внутри коллекции логично обращаться по ID /students/lastname/ivanov/1231231213.json

Когда мы возвращаем объекты в ответ на GET-запрос, имеет смысл отдавать полный набор атрибутов, независимо от пути.
Это позволяет упростить и унифицировать код клиента.

А вот когда мы передаём объект в PUT, возникают варианты.
По строгой REST-конвенции, надо передавать всё (т.к. PUT принимает представление полного ресурса).
Но я встречал довольно много расслабленных трактовок, в которых PUT принимает и частичный апдейт, т.е. ведёт себя как PATCH.
Особенно это популярно тогда, когда в представление объекта включается всякая readonly-информация из системы, или какие-то значения по умолчанию.
Ну, там, помимо LastName и FirstName, у нас будет DisplayName. Если его не передать явно, то оно будет установлено в LastName + FirstName. В строгой трактовке REST так делать нельзя — если клиент не передал DisplayName в PUT, это эквивалентно DisplayName = null, и надо уважать требование клиента.

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

В общем, если у вас не поддерживается PATCH, то я бы сделал ID, да и прочие атрибуты в PUT, опциональными.
А если PATCH есть, то можно кое-что и ужесточить.

При несоответствии значения ID в теле значению в пути, нужно отдавать код 409.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
http://rsdn.org/File/5743/rsdnaddict.GIF
Re: REST API: параметры в адресе и в теле запроса
От: Qulac Россия  
Дата: 19.09.22 06:09
Оценка: -1
Здравствуйте, Shmj, Вы писали:

S>Как вы решаете когда параметр поместить в адрес а когда в тело запроса?


S>Вот такая цитата:


S>

S>Например, если мы создаем REST API для обновления сведений об ученике с помощью PUT (метод HTTP), тогда URI запроса будет {server_host}/students/{student_id}а тело запроса будет таким:

S>

S>{
S>  "id": student_id,
S>  "name": "student name",
S>  "school_name": "school name"
S>}
S>


S>Я много раз видел, как разработчики путаются в том, почему нам нужно отправлять один и тот же параметр в несколько мест. Например, в приведенном выше примере мы отправляем student_id к параметру пути, а также к телу запроса. Может показаться, что мы отправляем повторяющуюся информацию через API, но помните, что параметры тела запроса и пути имеют разные значения и должны использоваться для той цели, которой они будут служить.

S>Ниже объясняется, почему мы не можем удалить student_id из параметров пути и тела запроса.

S>Тело запроса используется для отправки и получения данных через REST API. Если мы используем POST/PUT API, то на основе контракта REST API мы должны отправлять всю информацию о ресурсе, потому что эти методы работают со всем ресурсом. В приведенном выше примере student_id также является частью этого ресурса, поэтому он должен присутствовать в теле запроса, иначе тело запроса сможет представлять всю информацию о ресурсе.

S>После удаления student_id из тела запроса у нас будет следующее тело запроса.

S>
S>{
S>  "name": "student name",
S>  "school_name": "school name"
S>}
S>


S>Представляет ли это тело запроса всю информацию о ресурсах? Нет. Так что это нарушение контракта REST.

S>Итак, чтобы представить состояние ресурса, нам нужно отправить student_id в теле запроса, а чтобы однозначно идентифицировать ресурс, нам нужно отправить student_id в параметре пути.


S>Т.е. предлагается передавать и в адресе и в теле в данном случае. И вопрос такой — а если в адресе один ID а в теле другой — какую ошибку вернуть? И как это вообще трактовать?


Вопрос из категории: Вам шашечки или ехать? Мне важней ехать. Вот отрывок из запроса к реальному серверу:
{    "method": "updateSchedule",    "params": {      "resourceExternal": {


Используйте http-протокол как транспорт, зачем изголяться?
Программа – это мысли спрессованные в код
Re: REST API: параметры в адресе и в теле запроса
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 19.09.22 09:53
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Как вы решаете когда параметр поместить в адрес а когда в тело запроса?

Если параметр — это ключ или часть ключа, то в адрес. Если параметр для поиска\фильтра, то в query string. В остальных случаях в тело.


S>Т.е. предлагается передавать и в адресе и в теле в данном случае.

Можно просто игнорировать Id в теле, в asp.net это делается легко.


S>И вопрос такой — а если в адресе один ID а в теле другой — какую ошибку вернуть?

Если проверяется ID в теле, то 400 Bad Request

S>И как это вообще трактовать?

Как угодно, как проще будет сделать.
Re[2]: REST API: параметры в адресе и в теле запроса
От: maxkar  
Дата: 19.09.22 10:00
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А вот когда мы передаём объект в PUT, возникают варианты.

S>По строгой REST-конвенции, надо передавать всё (т.к. PUT принимает представление полного ресурса).
S>Но я встречал довольно много расслабленных трактовок, в которых PUT принимает и частичный апдейт, т.е. ведёт себя как PATCH.
Это вообще проблемы HTTP-протокола. PUT идемпотентный, но имеет семантику "перезаписи" объекта/представления. А PATCH в общем случае не является идемпотентным. Поэтому если хочется сделать красиво и согласно спецификации, приходится что-нибудь придумывать. Во многих случаях можно частичное обновление вынести в подресурс (например, /orders/<id>/status). Но вообще — да, не хватает в протоколе глаголов вроде ADVANCE для перемещения по конечному автомату. В этом случае он может выполнять переход (если допускается), может говорить, что состояние уже в прошлом (сейчас это conflict, но мне не нравится давать ошибку, приходится отвечать 202 Accepted) а может быть несовместимое состояние, где переход не допускается (а вот здесь уже будет 409).

S>Особенно это популярно тогда, когда в представление объекта включается всякая readonly-информация из системы, или какие-то значения по умолчанию.

S>Ну, там, помимо LastName и FirstName, у нас будет DisplayName. Если его не передать явно, то оно будет установлено в LastName + FirstName. В строгой трактовке REST так делать нельзя — если клиент не передал DisplayName в PUT, это эквивалентно DisplayName = null, и надо уважать требование клиента.
В какой-то степени это разруливается с помощью Content-Type в запросе (разработчики в основной массе такого не умеют обрабатывать на сервере, но это уже другая история). Например, "application/full-student-info;f=json;v=1" может подразумевать, что установлены все поля. Если DisplayName не установлено, оно должно быть установлено в null (или, например, должно присутствовать). А вот "application/summary-student-info;f=json;v=1" может не включать DipslayName, если оно установлено в "значение по умолчанию". В этом случае PUT с summary как раз подразумевает, что DisplayName может отсутствовать и при этом должен быть вычислен автоматически (при этом можно отличать null от undefined). Простой сервер всегда может отвечать full, более сложный может правильно генерировать summary (там нужно аккуратно смотреть, когда сделан display name). Ну и всякие вложенные объекты можно контроллировать через параметры Content-Type.

S>При несоответствии значения ID в теле значению в пути, нужно отдавать код 409.

А не 422? 409 не очень подходит для отсутствущего ресурса (т.е. для создания нового объекта).
Re: REST API: параметры в адресе и в теле запроса
От: Ночной Смотрящий Россия  
Дата: 19.09.22 14:31
Оценка: +1
Здравствуйте, Shmj, Вы писали:

S>Как вы решаете когда параметр поместить в адрес а когда в тело запроса?


query parameters обычно содержат информацию для поиска ресурса или для управления тем в каком виде она отдается. Другими словами для фильтров и проекций. Данные ходят через body. Как правило, это приводит к тому, что параметры options, get, head, delete передаются в url, параметры post, put, patch — в теле.
Помимо query string есть еще параметры в path и в хидерах. Первый случай используется исключительно для передачи уникального и единственного идентификатора ресурса в любых методах. Второй — для передачи информации, ортогональной специфике конкретного метода, что то типа аспектов.

S>Ниже объясняется, почему мы не можем удалить student_id из параметров пути и тела запроса.


Мутно очень объясняется. Тут, видимо, имеется в виду что PUT может позволять изменять id в теле. Что, как по мне, само по себе весьма криво.

S>Если мы используем POST/PUT API


Что такое "POST/PUT API"?

S>, то на основе контракта REST API мы должны отправлять всю информацию о ресурсе, потому что эти методы работают со всем ресурсом.


Это требование только для PUT. Для POST такого требования нет.

S> В приведенном выше примере student_id также является частью этого ресурса, поэтому он должен присутствовать в теле запроса


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

Не знаю откуда твоя цитата, но написано там крайне мутно и не видно чтобы автор вообще понимал о чем он пишет. Начни отсюда.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[3]: REST API: параметры в адресе и в теле запроса
От: Ночной Смотрящий Россия  
Дата: 19.09.22 14:45
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Но вообще — да, не хватает в протоколе глаголов вроде ADVANCE для перемещения по конечному автомату.


Чем он будет лучше использования существующего POST?
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[2]: REST API: параметры в адресе и в теле запроса
От: Ночной Смотрящий Россия  
Дата: 19.09.22 14:45
Оценка:
Здравствуйте, Qulac, Вы писали:

Q>Используйте http-протокол как транспорт, зачем изголяться?


https://aws.amazon.com/ru/what-is/restful-api/#What_are_the_benefits_of_RESTful_APIs.3F

P.S. Имей уважение к собеседникам, не цитируй ненужное.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[4]: REST API: параметры в адресе и в теле запроса
От: maxkar  
Дата: 26.09.22 10:39
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

M>>Но вообще — да, не хватает в протоколе глаголов вроде ADVANCE для перемещения по конечному автомату.

НС>Чем он будет лучше использования существующего POST?

Нет цели сделать лучше. Есть цель сделать по-другому. А если серьезно — новый глагол будет идемпотентным (POST в общем случае — нет). При этом семанитка идемпотентности у него — выбор "максимума" из текущего состояния и запроса, state := max(state, req). Для сравнения POST это state := req, DELETE — state := null.

Переходы задаются на множестве частично-упорядоченных состояний. Соответственно коды возврата соответствуют состояниям на этом автомате:
Ну и в отличие от PUT хорошо бы предусмотреть "частичное" представление в исходном запросе (т.е. что-то по мотивам PATCH).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.