JSON — JavaScript Object Notation, «нотация JavaScript-объектов». Это текстовый формат для представления структурированных данных. Если вы видели объект в JavaScript, вы уже почти знаете JSON.
Как выглядит JSON
{
"id": 42,
"title": "Заметка",
"isPublished": true,
"views": null,
"tags": ["css", "html"],
"author": {
"name": "Anna",
"age": 28
}
}
В JSON есть всего шесть типов значений:
- строка — всегда в двойных кавычках: "hello";
- число — целое или дробное, без кавычек: 42, 3.14;
- булево — true или false;
- null — null, «значения нет»;
- массив — список значений в квадратных скобках: [1, 2, 3];
- объект — пары «ключ: значение» в фигурных скобках, как пример выше.
Вложенность любой глубины — объект внутри массива внутри объекта внутри массива. Сервер вернёт — разберёте.
Где JSON отличается от JavaScript-объектов
Многие новички путают JSON с JS-объектами и пишут в JSON-файле такое, что валидатор сразу ругается. Запомните три отличия:
- Ключи всегда в двойных кавычках. Не одинарных, не без кавычек. В JavaScript {name: "Anna"} валидно, в JSON {"name": "Anna"} обязательно.
- Никаких комментариев. Ни //, ни /* */. JSON — чисто формат данных, не код.
- Никаких висящих запятых после последнего элемента. В JavaScript [1, 2, 3,] допустимо, в JSON — синтаксическая ошибка.
Ещё в JSON нет undefined, function, Date, Map, Set. Только шесть типов, перечисленных выше. Если в JS-объекте было поле undefined, после JSON.stringify оно просто исчезнет. Date превратится в строку. Функции выкинутся.
Откуда взялся JSON и почему он победил
До JSON в вебе для обмена данными между клиентом и сервером использовался XML. Тот же пост выглядел бы примерно так:
<post>
<id>42</id>
<title>Заметка</title>
<tags>
<tag>css</tag>
<tag>html</tag>
</tags>
</post>
Если посчитать символы, JSON получается короче. На клиенте парсинг XML требует библиотек или громоздкого DOMParser. JSON в JavaScript парсится одной встроенной функцией: JSON.parse. Плюс структура JSON один в один ложится на JS-объекты — никаких атрибутов отдельно от вложенных тегов, никаких пространств имён.
За пятнадцать лет JSON практически вытеснил XML из веб-API. XML ещё встречается в корпоративных системах, банковских интеграциях, SOAP-сервисах — но новые REST API почти всегда говорят на JSON.
JSON.parse и JSON.stringify
В браузере и в Node.js есть две встроенные функции для работы с JSON.
JSON.parse(текст) — превращает JSON-строку в JS-значение:
const text = '{"id": 42, "title": "Заметка"}';
const post = JSON.parse(text);
post.id; // 42
post.title; // "Заметка"
JSON.stringify(значение) — превращает JS-значение в JSON-строку:
const data = { id: 42, title: "Заметка", tags: ["css"] };
const text = JSON.stringify(data);
// '{"id":42,"title":"Заметка","tags":["css"]}'
В контексте fetch мы будем встречать обе:
- response.json() — читает тело ответа и сразу зовёт JSON.parse под капотом. Возвращает уже готовый JS-объект.
- body: JSON.stringify(...) — превращает JS-объект в JSON-строку и кладёт её в тело запроса.
Это два самых частых вызова в коде, который работает с REST API. Привыкайте.
Типичные ошибки JSON
На что наступают новички:
- «Unexpected token» при парсинге. Скорее всего, в ответе пришёл не JSON. Часто это HTML-страница с ошибкой сервера. Проверьте статус и Content-Type ответа перед response.json().
- «Unexpected end of JSON input». Тело пустое (статус 204) или оборвано. Не зовите .json() на ответах, в которых тела нет.
- Объект превратился в "[object Object]". Где-то забыли JSON.stringify и отправили объект сразу в body. fetch привёл его к строке через toString(), получился мусор.
- Поле undefined исчезло после JSON.stringify. Это не баг, это спецификация. Если поле важное, явно ставьте null.
На этом теоретическая база готова. В следующем модуле разберём набор HTTP-методов и статус-кодов — после чего можно будет наконец писать код.