Вопрос или проблема
Я пытаюсь изменить спецификацию OpenAPI, сделав все параметры допускающими значение null. Определение параметра выглядит следующим образом:
{
"name": "foo",
"required": true,
"type": "string"
}
Они содержатся в массиве parameters
, который может находиться в любом месте документа. Мне нужно добавить "x-nullable": true
к любому параметру, содержащему свойство type
.
Пример данных:
{
"parameters": [
{"notype": "x"},
{"type": "x"}
],
"foo": {
"parameters": [
{"type": "y"}
]
},
"bar": {
"baz": {
"parameters": [
{"type": "z"}
]
}
}
}
Желаемый результат:
{
"parameters": [
{"notype": "x"},
{
"type": "x",
"x-nullable": true
}
],
"foo": {
"parameters": [
{
"type": "y",
"x-nullable": true
}
]
},
"bar": {
"baz": {
"parameters": [
{
"type": "z",
"x-nullable": true
}
]
}
}
}
Самое близкое, чего мне удалось достичь, это это:
.. | (.parameters[] | select(.type)) += {"x-nullable":true}
Это успешно изменяет один из элементов в моем тестовом документе, но результаты непоследовательны и кажутся зависящими от структуры, выбранной для образца данных.
Следующее выражение jq
применяет обновление к значениям всех ключей parameters
, найденных в документе. Предполагается, что ключ parameters
всегда относится к массиву. Обновление назначает true
ключу x-nullable
всех элементов массива с ключом type
.
Рекурсия выполняется с помощью walk()
(применяет выражение к каждому значению в документе рекурсивно), а не с помощью оператора рекурсивного спуска ..
(извлекает каждое значение документа рекурсивно).
walk(
if type == "object" and has("parameters")
then
.parameters |= map(select(has("type"))."x-nullable" = true)
else
.
end
)
Безопаснее использовать select(has("type"))
для выбора объектов, имеющих поле type
, поскольку использование select(.type)
пропустило бы объекты, у которых значение type
было false
или null
.
Тестирование на образце документа в вопросе:
$ jq 'walk(if type == "object" and has("parameters") then .parameters |= map(select(has("type"))."x-nullable" = true) else . end)' file
{
"parameters": [
{
"notype": "x"
},
{
"type": "x",
"x-nullable": true
}
],
"foo": {
"parameters": [
{
"type": "y",
"x-nullable": true
}
]
},
"bar": {
"baz": {
"parameters": [
{
"type": "z",
"x-nullable": true
}
]
}
}
}
Ответ или решение
Изменение спецификации OpenAPI, чтобы все параметры стали допускающими null, может быть сложной задачей из-за глубины и структуры JSON-документа. Ваша цель — добавить "x-nullable": true
ко всем параметрам, которые содержат свойство type
. Это изменение должно быть выполнено для параметров в parameters
массива, который может находиться в любом месте документа. Чтобы решить эту проблему эффективно, вам потребуется использовать утилиту для работы с JSON, такую как jq
, которая позволяет манипулировать данными на основе соответствующих условий.
Теория
jq
— это мощный инструмент командной строки, используемый для обработки и фильтрации данных JSON. Его основной задачей является выполнение операций по спецификации JSON и выборки данных на основе указанных условий. В данном контексте, наиболее подходящий подход будет включать использование walk()
функции, которая применяется ко всем значениям в документе рекурсивно. Это позволяет модифицировать все необходимые параметры, вне зависимости от их положения в JSON-структуре.
Функция walk()
применяет определенное выражение к каждому значению в документе, проверяя, является ли текущее значение объектом, содержащим массив parameters
. При нахождении такого массива, каждое из его значений проверяется на наличие ключа type
, и если такой ключ присутствует, добавляется "x-nullable": true
.
Пример
Рассмотрим следующий пример JSON-документа:
{
"parameters": [
{"notype": "x"},
{"type": "x"}
],
"foo": {
"parameters": [
{"type": "y"}
]
},
"bar": {
"baz": {
"parameters": [
{"type": "z"}
]
}
}
}
Ожидается, что в результате применения jq
выражения все параметрические объекты с наличием ключа type
будут модифицированы следующим образом:
{
"parameters": [
{"notype": "x"},
{
"type": "x",
"x-nullable": true
}
],
"foo": {
"parameters": [
{
"type": "y",
"x-nullable": true
}
]
},
"bar": {
"baz": {
"parameters": [
{
"type": "z",
"x-nullable": true
}
]
}
}
}
Применение
Для достижения этого результата, можно использовать следующее jq
выражение:
jq 'walk(if type == "object" and has("parameters") then .parameters |= map(select(has("type"))."x-nullable" = true) else . end)' файл
Объяснение выражения:
-
walk(): Это выражение рекурсивно проходит через все элементы JSON. Оно проверяет каждый элемент на соответствие условиям.
-
if type == "object" and has("parameters"): Проверяет, является ли текущий элемент объектом и содержит ли он ключ
parameters
. -
.parameters |= map(…): Применяет функцию
map()
к массивуparameters
, чтобы изменять каждый элемент в массиве. -
select(has("type")): Выбирает только те объекты внутри массива
parameters
, которые имеют ключtype
. -
"x-nullable" = true: Устанавливает свойство
"x-nullable": true
для каждого объекта, где присутствует ключtype
.
Таким образом, такая конфигурация выражения jq
обеспечивает точное модифицирование JSON-документа, вне зависимости от его глубины и структуры.
Итог
Изменение JSON-документа, как описано выше, позволяет легко корректировать структуры данных в соответствии с требованиями OpenAPI, обеспечивая гибкость и точность в обработке данных. Это решение не только делает параметры допускающими null, но и поддерживает структурную целостность и допустимость JSON-документа, что особенно важно для сложных конфигураций API.