REST API для обновления информации с пустыми или нулевыми значениями - PullRequest
0 голосов
/ 07 января 2020

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

Предположим, у нас есть таблица с 10 столбцами, и мы можем запросить эти 10 столбцов с помощью REST (GET). Ответ JSON будет содержать все 10 полей. Это просто и работает без проблем.

Следующим шагом является то, что кто-то хочет создать новую запись через POST. В этом случае человек отправляет только 8 из 10 полей в запросе JSON. Затем мы заполним только 8 полей в базе данных (остальные будут NULL). Это также работает без проблем.

Но что произойдет, если кто-то захочет обновить запись? Мы видим здесь различные возможности с преимуществами и недостатками.

  1. Отправляется только то, что должно быть обновлено. Проблема: Как вы можете явно очистить / удалить поле? Если в JSON передается «NULL», мы получаем NULL в объекте, но любое другое поле, которое не было передано, также равно NULL. Поэтому мы не можем различить guish, какое поле может быть удалено, а какое поле не может быть затронуто.

  2. Полный объект отправлен. Проблема: Здесь объект может быть получен через GET раньше, изменен соответствующим образом и возвращен через PUT. Теперь мы получаем всю информацию и можем записать ее обратно в базу данных. Потому что пустые поля либо были ранее пустыми, либо были очищены пользователем.

Что происходит, если объекты расширяются обновлением API. Предположим, мы расширили базу данных еще на пять полей. Пользователь API делает GET, получает 15 полей, но может прочитать только 10 полей, которые он знает на своей странице (потому что он еще не обновил свою сторону). Затем он меняет некоторые из 10 полей и отправляет их обратно через PUT. Затем мы обновим только 10 полей на нашем сайте, и 5 новых полей будут удалены из базы данных.

Или вам нужно создать отдельную конечную точку для каждого поля? Мы также подумали о создании карты с ключом / значением, что именно должно быть изменено.

О технике: Мы используем Wildfly 15 with Resteasy and Jackson.

Например:

База данных в начале

+----+----------+---------------+-----+--------+-------+
| ID | Name     | Country       | Age | Weight | Phone |
+----+----------+---------------+-----+--------+-------+
| 1  | Person 1 | Germany       | 22  | 60     | 12345 |
| 2  | Person 2 | United States | 32  | 78     | 56789 |
| 3  | Person 3 | Canada        | 52  | 102    | 99999 |
+----+----------+---------------+-----+--------+-------+

GET ... / person / 2

{
   "id" : 2,
   "name" : "Person 2",
   "country" : "United States",
   "age" : 22,
   "weight" :62,
   "phone": "56789"
}

Теперь я хочу обновить свой вес и убрать номер телефона

PUT ... / person / 2

{
   "id" : 2,
   "name" : "Person 2",
   "country" : "United States",
   "age" : 22,
   "weight" :78
}

или

{
   "id" : 2,
   "name" : "Person 2",
   "country" : "United States",
   "age" : 22,
   "weight" :78,
   "phone" : null
}

Теперь база данных должна выглядеть следующим образом:

+----+----------+---------------+-----+--------+-------+
| ID | Name     | Country       | Age | Weight | Phone |
+----+----------+---------------+-----+--------+-------+
| 1  | Person 1 | Germany       | 22  | 60     | 12345 |
| 2  | Person 2 | United States | 32  | 78     | NULL  |
| 3  | Person 3 | Canada        | 52  | 102    | 99999 |
+----+----------+---------------+-----+--------+-------+

Проблема в

Мы расширяем таблицу следующим образом (продажа)

+----+----------+---------------+-----+--------+--------+-------+
| ID | Name     | Country       | Age | Weight | Salery | Phone |
+----+----------+---------------+-----+--------+--------+-------+
| 1  | Person 1 | Germany       | 22  | 60     | 1929   | 12345 |
| 2  | Person 2 | United States | 32  | 78     | 2831   | NULL  |
| 3  | Person 3 | Canada        | 52  | 102    | 3921   | 99999 |
+----+----------+---------------+-----+--------+--------+-------+

Человек, использующий API, не знает, что в * 1063 есть новое поле * за зарплату. И этот человек сейчас хочет изменить номер телефона кого-то еще раз, но не отправляет зарплату. Это также опустошило бы зарплату:

{
   "id" : 3,
   "name" : "Person 3",
   "country" : "Cananda",
   "age" : 52,
   "weight" :102,
   "phone" : null
}


+----+----------+---------------+-----+--------+--------+-------+
| ID | Name     | Country       | Age | Weight | Salery | Phone |
+----+----------+---------------+-----+--------+--------+-------+
| 1  | Person 1 | Germany       | 22  | 60     | 1929   | 12345 |
| 2  | Person 2 | United States | 32  | 78     | 2831   | NULL  |
| 3  | Person 3 | Canada        | 52  | 102    | NULL   | NULL  |
+----+----------+---------------+-----+--------+--------+-------+

И зарплата не должна быть нулевой, потому что она не была установлена ​​внутри JSON запроса

Ответы [ 5 ]

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

Вы можете десериализовать вашу JSON на карту. Таким образом, если свойство не было отправлено, оно не отображается на карте. Если его ноль, его внутри карты будет нулевое значение.

  ObjectMapper mapper = new ObjectMapper();
  TypeReference<HashMap<String, Object>> typeReference = new TypeReference<>() {};
  HashMap<String, Object> jsonMap = mapper.readValue(json, typeReference);
  jsonMap.entrySet().stream().map(Map.Entry::getKey).forEach(System.out::println);

Не очень удобное решение, но оно может работать для вас.

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

Предположим, мы расширили базу данных еще на пять полей. Пользователь API делает GET, получает 15 полей, но может прочитать только 10 полей, которые он знает на своей странице (потому что он еще не обновил свою сторону). Затем он меняет некоторые из 10 полей и отправляет их обратно через PUT. Затем мы обновим только 10 полей на нашем сайте, и 5 новых полей будут удалены из базы данных.

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

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

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

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

Лицо, использующее API, не знает, что в JSON есть новое поле для зарплаты.

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

Существует множество предшествующего уровня техники от 15-20 лет до go, потому что люди пишут сообщения в XML столкнулись с точно такими же проблемами. Они оставили часть своих знаний позади. Самый простой способ найти это - поиск некоторых ключевых фаз; например, must ignore или must forward.

См .:

События в хранилище событий имеют такие же проблемы. Книга Грега Янга Управление версиями в системе источников событий охватывает много той же основы (представления событий также являются сообщениями).

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

Обычный способ - отслеживать изменения в объекте POJO.

  1. Загрузить Dog с помощью color = черный, size = ноль и age = ноль
  2. Установите size в ноль (установщик пометит это поле как измененное)
  3. Запустить обновление SQL

POJO будет иметь внутреннее состояние, которое известно, что size было изменено и, таким образом, включить это поле в ОБНОВЛЕНИЕ. age, с другой стороны, никогда не был установлен, и поэтому оставлен без изменений. JOOQ работает так, я уверен, что есть другие.

0 голосов
/ 07 января 2020
  1. Отправляется только то, что должно быть обновлено. Проблема: Как вы можете явно очистить / удалить поле? Если в JSON передается «NULL», мы получаем NULL в объекте, но любое другое поле, которое не было передано, также равно NULL. Поэтому мы не можем различить guish, какое поле может быть удалено, а какое поле не может быть затронуто.

Вы обнаружили подлинную проблему; Я тоже с этим сталкивался. Я думаю, что разумно не предоставить техническое решение для этого, а скорее задокументировать использование API, чтобы позволить вызывающему абоненту знать, как оставить поле или отправить его как null. Конечно, если предположить, что проверки на стороне сервера являются жесткими и обеспечивают работоспособность.

Полный объект отправлен. Проблема: Здесь объект может быть получен через GET раньше, изменен соответствующим образом и возвращен через PUT. Теперь мы получаем всю информацию и можем записать ее обратно в базу данных. Поскольку пустые поля либо были уже пустыми, либо были очищены пользователем.

Это "прямолинейный" и должен быть задокументирован в API.

Что происходит, если объекты расширяются обновлением API.

С учетом того, что на документацию возложена обязанность вызывающего абонента, это также обрабатывается неявно.

Или вам нужно создать отдельную конечную точку для каждого поля?

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

0 голосов
/ 07 января 2020

Вы можете управлять пустыми или нулевыми значениями, как показано ниже

public class Person{

    @JsonInclude(JsonInclude.Include.NON_NULL) 
    private BigDecimal salary;  // this will make sure salary can't be null or empty//

    private String phone;   //allow phone Number to be empty
    // same logic for other fields
}

i) Когда вы обновляете вес и удаляете номер телефона, попросите клиента отправить поля, которые необходимо обновить, вместе с идентификатором записи, т.е. идентификатором в этом случае

{
   "id" : 2,
   "weight" :78,
   "phone" : null  
}

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

...