Откуда берётся неряшливый JSON
Большая часть JSON, который встречается на практике, написана одной программой для другой, поэтому приходит одной длинной строкой: ответ API, скопированный со вкладки «Сеть» в браузере, тело вебхука в лог-файле, значение конфига, хранящееся в столбце базы данных. Читать однострочник в 4000 символов, чтобы найти одно вложенное поле, медленно, и легко ошибиться. Форматирование выносит каждый ключ на отдельную строку и делает отступ на каждом уровне, так что структура становится видна с одного взгляда.
Обратная задача встречается не реже. Прежде чем вставить JSON в переменную окружения, строку запроса, тестовую фикстуру или сообщение в чате, его часто хочется сделать максимально компактным. Минификация убирает все пробелы и переносы строк вне строковых значений; типичный конфиг с отступами уменьшается на 20–40 процентов в зависимости от глубины вложенности.
Что форматировщик делает с данными
Входные данные разбираются встроенным JSON-парсером браузера и записываются обратно с выбранным отступом: 2 пробела, 4 пробела или табуляция. «Минифицировать» идёт тем же путём, только вовсе без отступов. Поскольку документ собирается заново из разобранного значения, а не правится как текст, некоторые детали могут измениться, и стоит знать какие:
- Запись чисел нормализуется.
1.0становится1,1e3—1000, а-0—0. Значение то же, написание — нет. - Очень большие целые теряют точность. JavaScript хранит числа как 64-битные числа с плавающей точкой, которые точны только до 9 007 199 254 740 991. 19-значный ID вроде
12345678901234567890вернётся как12345678901234567000. Если в ваших данных есть ID в стиле Snowflake, bigint из базы данных или суммы платежей в минимальных единицах такого масштаба, сверьте результат перед использованием. - Unicode-последовательности декодируются.
"caf\u00e9"записывается обратно как"café". Оба варианта — валидный JSON и означают одну и ту же строку. - Повторяющиеся ключи схлопываются. Если объект содержит один и тот же ключ дважды, выживает только последнее значение. Стандарт JSON оставляет поведение с дубликатами неопределённым, и большинство парсеров ведут себя именно так.
- Целочисленные ключи переезжают в начало. Ключи, похожие на неотрицательные целые числа, например
"2"или"10", ставятся первыми по возрастанию, впереди всех остальных ключей. Это правило объектов JavaScript, а не JSON. Обычные текстовые ключи сохраняют исходный порядок.
Для типичных ответов API всё это не важно, но важно, если вы собираетесь закоммитить отформатированный файл и хотите минимальный diff.
Как читать позицию ошибки
Когда разбор не удаётся, инструмент запускает собственный небольшой сканер, чтобы найти первый символ, после которого документ не может оставаться валидным, и сообщает его позицию в виде строки и символа.
Указанное место — то, где парсер сдался, а это не всегда то место, где допущена ошибка:
- Запятая в конце в
[1, 2, ]указывается на закрывающей скобке, потому что там ожидалось значение. - Пропущенная запятая между двумя свойствами указывается в начале второго ключа.
- Пропущенная закрывающая фигурная или квадратная скобка указывается в самом конце входных данных — иногда на сотни строк ниже настоящей проблемы. Ищите последний открытый объект или массив.
- Строка без закрывающей кавычки указывается в конце своей строки, потому что «сырой» перенос строки внутри строки JSON запрещён. Та же позиция появится для многострочного текста, вставленного в значение; переносы строк там нужно записывать как
\n.
Если на входе на самом деле не JSON, а литерал объекта JavaScript, YAML или словарь Python, напечатанный с одинарными кавычками, ошибка появится в первой-второй строке. Эти форматы похожи, но не взаимозаменяемы.
Как выбрать отступ
- 2 пробела — стандарт в большинстве инструментов JavaScript, файлах
package.jsonи многих стайлгайдах. Глубоко вложенные данные не уползают за правый край экрана. - 4 пробела — то, что выдаёт
json.dumps(indent=4)в Python; для неглубоких документов читается легче. - Табуляция позволяет каждому читателю выбрать визуальную ширину в своём редакторе и даёт файлы чуть меньше, чем с 4 пробелами.
Для файлов, которые живут в репозитории, используйте то, что уже принято в проекте: смешение стилей делает каждый diff шумным.
Что дальше делать с отформатированными данными
Когда структура читаема, другие задачи становятся проще. Чтобы разложить массив записей в таблицу, сконвертируйте его инструментом JSON в CSV. Чтобы увидеть, что именно изменилось между двумя версиями ответа, отформатируйте обе с одинаковым отступом и сравните их в инструменте сравнить тексты: одинаковое форматирование означает, что diff покажет только настоящие изменения. Всё происходит на странице, поэтому токены и персональные данные из ответа остаются на вашем устройстве.