Как реализовать сложные условные массовые частичные обновления через JSON API?

В протоколе HTTP есть методы POST и PATCH для частичного обновления. В методе PATCH для JSON API есть RFC 5789, RFC 6902, RFC 7396.

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

Допустим, у нас есть конечная точка API "/members", которая напоминает большую коллекцию с тысячами записей, где каждая запись имеет десятки полей. Таким образом, клиенты частично считывают эти значения с помощью метода "GET /members?fields=f1,f2,f3" с разбиением на страницы, и каждый клиент читает только подмножество полей, необходимых для его текущей задачи.

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

{
"email": "[email protected]",
"optional1": "x",
"optional2": "x",
"optional3": "x"
}

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

Таким образом, клиент А отправил бы запрос со значениями A для массового исправления, которому было бы разрешено перезаписывать значение поля "optional1" только потому, что это поле необходимо для его задачи. И этот клиент также укажет значение для поля "optional2" для новых записей. А тот клиент вообще не указал поле "optional3".

{
"email": "[email protected]",
"optional1": "A",
"optional2": "A"
}

Пока эта запись новая, она полностью записывается в хранилище. Затем клиент Б отправит запрос со значениями B для массового исправления, которому будет разрешено перезаписывать значение поля "optional2" только потому, что это поле необходимо для его задачи.

{
"email": "[email protected]",
"optional1": "B",
"optional2": "B",
"optional3": "B"
}

Поскольку запись уже существует, поле "optional1" этой записи должно остаться с тем же старым значением A, поскольку это поле не является обязательным, значение поля "optional2" должно быть перезаписано новым значением B, поскольку это поле является обязательным, а значение поля "optional3" должно получить значение B, потому что это поле было просто пустым. Объединенный результат действий должен быть следующим.

{
"email": "[email protected]",
"optional1": "A",
"optional2": "B",
"optional3": "B"
}

Таким образом, поведение зависит от существования записи. Ребята, как бы вы реализовали этот многоразовый метод конечной точки JSON API для параллельных частичных обновлений таких коллекций со сложными условиями, которые позволили бы клиентам этого API перезаписывать только подмножество полей в записи, если эта запись уже существовала и содержала некоторые значения?

Решение RFC 6902 не подходит, поскольку обе операции add и replace фактически заменяют значение.

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

replace — операция замены заменяет значение в целевом местоположении новым значением. Объект операции ДОЛЖЕН содержать элемент значения, содержимое которого определяет замещающее значение.

Вы можете увидеть, как это соответствует Java Map.put().

Если карта ранее содержала сопоставление для ключа, старое значение заменяется указанным значением.

Но отсутствующая функция скорее соответствует Java Set.add().

Добавляет указанный элемент в этот набор, если он еще не присутствует (дополнительная операция). Более формально добавляет указанный элемент e к этому набору, если набор не содержит элемента e2 такого, что (e==null ? e2==null : e.equals(e2)). Если этот набор уже содержит элемент, вызов оставляет набор без изменений и возвращает false.

Как бы вы сделали JSON API, который позволял бы выполнять оба типа операций для массового исправления очень большой коллекции с элементами, содержащими десятки необязательных полей?


Обновлять

Спасибо @chad-jensen за идею правил приоритизации атрибутов. Упомянутый документ предлагает достаточно гибкий подход, поэтому я попытался адаптировать его под свои нужды. Я думаю, что у меня будет две операции: инициализация с более низким приоритетом и добавление или, возможно, замена с более высоким приоритетом.

Тогда в моем примере данные JSON, отправленные клиентом A и клиентом B, будут выглядеть следующим образом.

Данные, отправленные Клиентом A, которые обновляют поле "optional2" с более низким приоритетом и обновляют поле "optional1" с наивысшим приоритетом.

{
    "email": "[email protected]",
    "initialize":
    {
        "optional2": "A"
    },
    "replace":
    {
        "optional1": "A"
    }
}

Данные, отправленные Клиентом B, которые обновляют поля "optional1" и "optional3" с более низким приоритетом и обновляют поле "optional2" с наивысшим приоритетом.

{
    "email": "[email protected]",
    "initialize":
    {
        "optional1": "B",
        "optional3": "B"
    },
    "replace":
    {
        "optional2": "B"
    }
}

person Ilia Sretenskii    schedule 27.09.2018    source источник
comment
Вы уверены, что этой архитектуре не нужен какой-то промежуточный уровень (мне хочется сказать, база данных) для управления всеми этими одновременными обновлениями, проверками полномочий и т. д.? Я не вижу, как вы собираетесь проверять эти обновления, например. для управления инцидентами, для начала. Хотя я, без сомнения, упускаю что-то важное!   -  person MandyShaw    schedule 27.09.2018
comment
Конечно, будет и аудит, и база данных, и все остальное. Вопрос был скорее о формате данных передачи JSON, который позволял бы устанавливать разные приоритеты источника для каждого поля. Кстати, я обновил исходный вопрос решением, основанным на этой идее уровней приоритета атрибутов.   -  person Ilia Sretenskii    schedule 28.09.2018


Ответы (1)


Вам понадобится своего рода сопоставление приоритетов, которое определяет, какие поля являются приоритетными для каждого клиента.

Кажется, что у вас это уже есть, но я предполагаю, что оно где-то хранится / сервер и / или клиент знают, какое поле у ​​них имеет наивысший приоритет (приоритет). Вам также может понадобиться узнать, какой клиент последний раз обновлял каждое поле.

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

Я нашел документ, который может прояснить, что я имею в виду (в нем содержится немного конкретики в отношении некоторых сторонних инструментов, но концепция есть): https://www.ibm.com/support/knowledgecenter/en/SSPLFC_7.2.0/UserGuide/c_cmdb_reconcilation_overview.html

person Chad Jensen    schedule 28.09.2018
comment
Спасибо, Чад. Я изучил упомянутый документ и сгенерировал решение на основе уровней приоритета атрибутов. Вы можете увидеть это в моем обновленном тексте вопроса. - person Ilia Sretenskii; 28.09.2018