Ресурс REST со свойством List

Мне нужна некоторая обратная связь по моей текущей архитектуре.

У меня есть ресурс "Человек", доступный через запросы GET и PUT:/users/people/{key}. Ресурс создает и принимает объекты "Person" в формате JSON.

Это пример JSON, который может вернуть GET /users/people/{key}:

{
 "age":29,
 "firstName":"Chiquita",
 "phoneNumbers":[
   {"key":"49fnfnsa0sas","number":"555-555-5555","deleted":false}
   {"key":"838943bdfb-f","number":"777-777-7777","deleted":false}
  ]
}

Как вы можете видеть, у "Person" есть некоторые типичные поля, такие как "firstName" и "age", а также более сложное поле типа коллекции: "phoneNumbers" .

Я пытаюсь разработать ресурсы, чтобы при их обновлении клиенту нужно было отправлять обратно поля, которые необходимо обновить. Например, чтобы обновить только человека firstName:

PUT users/people/{key}

{
 "firstName":"New first name",
}

Таким образом, гораздо меньше ненужной информации передается взад и вперед (в градусах меньше в зависимости от размера ресурса)

Мой вопрос: что мне делать с такими свойствами списка, как "phoneNumbers" . Должен ли я писать более сложный код, который проверяет существующие ключи PhoneNumber в старом списке и не трогает их, если они не указаны, обновляет их, если есть соответствующий ключ, и добавляет их, если есть номер телефона с новым ключом? Или я должен написать более простой код, который рассматривает каждое свойство списка "phoneNumbers" как просто другое поле, которое полностью перезаписывается, если оно включено в тело запроса "PUT"? Существует ли стандартный подход к этому, когда одна стратегия оказалась менее проблематичной, чем другая? или я должен использовать свое усмотрение?

Спасибо!

Ответ 1

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

  • Множество данных должно быть отправлено туда и обратно на изменение в типичных сценариях.
  • Несколько человек могут редактировать одного и того же человека одновременно.

Если объекты ваших людей велики, вы можете подумать о применении подхода diff/patch. Перед отправкой новой версии сравните ее со старой версией. Если одноэлементное поле (например, firstName) изменилось, просто перечислите его в свой объект JSON:

{
 "firstName":"New first name"
}

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

{
 "+phoneNumbers":[
  {"key":"123456789abc","number":"555-123-4567"}
 ],
 "-phoneNumbers":[
  "49fnfnsa0sas"
 ]
}

Вы также можете найти в Google "json diff" и узнать, полезны ли какие-либо результаты.

Как я уже говорил, если у вас нет веских оснований идти на эту глубину сложности, вероятно, лучше всего просто перезагрузить клиента весь объект для его обновления.

Ответ 2

Определение PUT состоит в том, что оно должно заменить семантику. Был введен глагол PATCH, позволяющий делать частичные обновления. См. http://tools.ietf.org/html/rfc5789

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

Ответ 3

Как говорили другие, PUT требует замены всего ресурса. Однако, как архитектор, вы можете спроектировать, что такое ресурс. Возможно, запись Person содержит номера телефонов в качестве части. Или, может быть, это больше похоже на то, как вы создадите реляционную базу данных с номерами телефонов в отдельной таблице. В этом случае GET/users/people/{key} получит только имя и возраст, и вы должны определить параметры запроса, если хотите получить номера телефонов вместе с именем. GET/users/userphone/{key} получит ресурс, содержащий номера телефонов человека, массив.

Возвращаясь к определению ресурса Person, содержащему телефонные номера внутри него, нет ничего плохого в использовании POST. Например, классическое использование POST - опубликовать комментарий к веб-странице или удалить комментарий. Нет причин, по которым вы не можете определить операцию POST для добавления или удаления номера телефона. POST - это метод "ничего", для хорошего или плохого.

(Я заметил, что кнопка здесь говорит "Опубликуйте свой ответ", а не "Положите свой ответ" и не без оснований.)