Возвращать разные JSON результаты для одного и того же запроса - это нарушение REST? - PullRequest
2 голосов
/ 24 января 2020

Обратите внимание на следующее от Roy Fielding относительно дизайна REST, руководящих принципов и принципов.

5.2.1.1 Ресурсы и идентификаторы ресурсов

Ключевая абстракция информации в REST - это ресурс. Любая информация, которая может быть названа, может быть ресурсом: документ или изображение, временная служба (например, «сегодняшняя погода в Лос-Анджелесе»), набор других ресурсов, не виртуальный объект (например, человек) и т. Д. , Другими словами, любой концепт, который может быть целью гипертекстовой ссылки автора, должен вписываться в определение ресурса.

Ресурс - это концептуальное отображение набора сущностей, а не объект, который соответствует отображению в любой конкретной точке в времени.

Точнее говоря, ресурс R представляет собой изменяющуюся во времени функцию членства MR (t), которая для времени t отображается на набор объектов или значений, которые эквивалентны. Значения в наборе могут быть представлениями ресурса и / или идентификаторами ресурса. Ресурс может отображаться на пустой набор, что позволяет делать ссылки на концепцию до того, как будет реализована любая реализация этой концепции - понятие, которое было чуждо большинству гипертекстовых систем до появления в Интернете [61]. Некоторые ресурсы имеют статус c в том смысле, что при рассмотрении в любое время после их создания они всегда соответствуют одному и тому же набору значений. Другие имеют высокую степень отклонения в их значении с течением времени.

Единственное, что требуется, чтобы быть stati c для ресурса, это семантика сопоставления, поскольку именно семантика - это то, что отличает один ресурс из другого.

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

Вот сценарий.

У меня есть веб-API с конечной точкой: http://www.myfakeapi.com/people

Когда клиент выполняет запрос GET к этой конечной точке, он получает список людей.

Person
{
  "Name": "John Doe",
  "Age": "23",
  "Favorite Color": "Green"
}

Хорошо, это круто.

Но разве это противоречит методам и принципам дизайна REST, если у меня есть «Персона», у которой нет избранного цвета, и я хочу вернуть ее так:

Person
{
  "Name": "Bob Doe",
  "Age": "23",
}

Или я должен возвращайте их так:

Person
{
  "Name": "Bob Doe",
  "Age": "23",
  "Favorite Color": null
}

Проблема в том, что клиент, запрашивающий ресурс, должен выполнить дополнительную работу, чтобы увидеть, существует ли свойство вообще. У некоторых людей есть любимые цвета, а у некоторых нет. Противозаконно ли принципам REST просто опускать свойство json «Любимый цвет», если они не существуют, или этому свойству должно быть присвоено «нулевое» или пустое значение?

Что говорит REST о это? Я думаю, что я должен вернуть нулевое значение и не изменять представление ресурса, который запрашивает клиент, с помощью , пропуская свойств.

Ответы [ 2 ]

1 голос
/ 24 января 2020

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

1) Предпочитаю перечисления (только если это имеет смысл для вашего варианта использования) )

{
  "Name": "Bob Doe",
  "Age": "23",
  "Favorite Color": NO_COLOR
}

Когда вы знаете значения для вашего свойства в начале, определите набор констант enum и назначьте значение по умолчанию, если свойство не применяется к пользователю. Это помогает несколькими способами:

  • Ваш клиент знает, каковы возможные значения, чтобы он мог соответствующим образом подготовить свою клиентскую систему.

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

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

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

2) Использовать Null - не создавать константы перечисления для всего

Бывают случаи, когда объект NULL вполне допустим. Например, в приведенном ниже примере имеет смысл использовать null, если нет любимой цитаты.

{
  "Name": "Bob Doe",
  "Age": "23",
  "Favorite Quote": null
}

3) Четко задокументируйте необходимые свойства

Если вы используете swagger для документации по остальному API, вы можете пометить обязательные свойства как необходимые. Те, которые не отмечены, являются необязательными. Таким образом, клиент будет готов обработать, если они имеют значение NULL или пустую строку. (Это должно применяться и к другим инструментам документирования API)

Плохая практика: я замечаю, что несколько пользователей кодируют таким образом, они отправляют ошибки в той же модели ответа, которую отправляют своим ответом об успешном выполнении 200. Направьте этот вопрос и ответ. Это определенно плохая практика. Не смешивайте два разных ответа и пометьте одно свойство как необязательное - используйте коды состояния, чтобы сообщить о любых проблемах. Я не говорю о частичном ответе здесь.

4) Добавить / изменить свойства (если вы не нарушаете контракт с клиентом)

Допустим, свойство Favorite Color добавлено позже, и в данный момент вы отправляете следующий ответ своему клиенту. Вы добавите sh ваш новый контракт своим клиентам, когда добавите Favorite Color, но ваши клиенты должны иметь отказоустойчивый код и обрабатывать неизвестные свойства. В Джексоне мы будем использовать DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES для этого. Неразрывные изменения не обязательно требуют v2.

Person
{
  "Name": "Bob Doe",
  "Age": "23",
}

Итак, ответ на ваш вопрос заключается в том, что вы должны начать смотреть на первые три варианта, пока вы разрабатываете свой API отдыха, вам не нужно пропускать какие-либо свойства. Но вам может потребоваться добавить несколько свойств позже (рассмотрено на # 4), что совершенно нормально.

1 голос
/ 24 января 2020

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

Потребитель вашего API должен знать, чего ожидать, и в идеале это должно быть хорошо задокументировано (мне для этого очень нравится использовать Swagger ). О любых изменениях в том, что ожидать, следует сообщать потребителям, возможно, в форме заметок о выпуске. Изменения, которые могут быть потенциально опасными для вашего потребителя, должны быть представлены в новой версии вашего API.

Так как ваши Person1 и Person2 являются технически различными объектными структурами, это может разрушиться само по себе (давайте посмотрим правде в глаза, мы не всегда находим крайние случаи в качестве разработчиков). Вы не просто хотите, чтобы ваш API работал на базовом уровне c, и он был бы чертовски доволен конечными пользователями - вы хотите разработать его с учетом требований конечного потребителя, чтобы облегчить им жизнь.

...