JSON — это один из самых популярных форматов обмена данными между бекэндом и фронтэндом. Еще JSON известен как JavaScript Object Notation. Он очень похож на то, как выглядят обычные JavaScript объекты, но также имеет свои особенности. Читается - “джейсон”, хотя часть твоих будущих коллег будут говорить и “джсон”, и “жсон”, и даже “жисон”.

JSON не накладывает никаких ограничений на язык программирования, который будет с ним работать. Ты можешь работать в организации, где часть бекэнд сервисов написана на Python, часть на Java, а фронт на JS и все они прекрасно обмениваются JSON сообщениями.

Хранение данных в формате JSON

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

(Почти) все должно быть обернуто в кавычки

В отличие от JavaScript, ты должен пользоваться только двойными кавычками и оборачивать в них все свойства объектов. Одинарные или обратные (косые) кавычки использовать нельзя.

В JS у нас был такой объект

{
  name: 'Jack',
  isMarried: false,
  age: 25,
}

А в JSON он станет таким

{
  "name": "Jack",
  "isMarried": false,
  "age": 25
}

Обрати внимание, что в JavaScript объектах наличие запятой после age: 25, является допустимым, а в JSON - нет.

Названия всех полей обернуты в двойные кавычки, а значения — не все. Числа и булевы значения хранятся без кавычек.

Объекты хранятся в фигурных скобках

Для хранения объектов используются фигурные скобки, как и в JS.

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

Массивы хранятся в квадратных скобках

Все точно как в JS, оборачиваем название массива в двойные кавычки, а сам массив указываем в квадратных скобках.

{
  "pets": ["Rex", "Sandy"]
}

Еще раз обращаем внимание, что в конце строки нет ни запятой, ни точки с запятой.

Все данные JSON в объекте хранятся как пары “ключ”:“значение”

Как и в JS, ты можешь добавлять в объект только пары ключ:значение. Если тебе нужно сохранить несколько значений без ключей, то тебе нужен массив.

Конвертация JavaScript объектов в JSON и обратно

Для конвертации из обычного JS объекта в JSON строку, тебе нужна функция JSON.stringify(obj). Она доступна без установки дополнительных модулей. Передаешь ей объект obj и на выходе получаешь JSON объект.

const user = {
  name: 'Jack',
  isMarried: false,
  age: 25,
}

const userJSON = JSON.stringify(user);
console.log(userJSON);   // {"name":"Jack","isMarried":false,"age":25}

Для конвертации из JSON в обычный объект, нам нужна функция JSON.parse(s). Даем строку в формате JSON на вход, получаем JS объект на выходе.

const jsonString = '{"name":"Jack","isMarried":false,"age":25}';
const parsedUser = JSON.parse(jsonString);

console.log(parsedUser);  // { name: 'Jack', isMarried: false, age: 25 }

Express.js и JSON

Так как мы знаем, что JSON объект — это строка, нам будет просто модифицировать сервер и вместо Hello, Express.js отправлять какой-нибудь объект.

Представим, что нам нужно передать на фронтэнд объект

{
  name: 'Hero',
  isLearning: true,
  level: 'apprentice',
}

Сделаем это несколькими способами. Во всех случаях фронтэнд получит одно и то же, в чем ты можешь убедиться с помощью запроса в браузере.

  1. Обычная строка:

    server.get('/', (req, res) => {
      return res.send('{"name":"Hero","isLearning":true,"level":"apprentice"}');
    })
    
  2. Объект, преобразованный с помощью JSON.stringify:

    server.get('/', (req, res) => {
      const user = { name: 'Hero', isLearning: true, level: 'apprentice' };
      return res.send(JSON.stringify(user));
    })
    
  3. Объект преобразованный с помощью res.json:

    server.get('/', (req, res) => {
      const user = { name: 'Hero', isLearning: true, level: 'apprentice' };
      return res.json(user);
    })
    

Повторю еще раз. Во всех случаях в итоге получится одно и то же. Мы отправим ответ со статусом 200 и строкой {"name":"Hero","isLearning":true,"level":"apprentice"}, которую получатель сможет использовать как ему захочется.

По правде говоря, между res.send и res.json есть разница и она состоит в типе ответа. Это специальный заголовок Content-Type, который в случае res.send устанавливается равным text/html, а для res.jsonapplication/json.

Используй res.json, если у тебя есть готовый объект, который ты хочешь отправить в формате JSON.

Третий пример самый удачный, так как нам нужно делать миниум лишних действий. Мы передаем объект в res.json и преобразование в JSON строку происходит внутри. Дополнительный (явный) вызов JSON.stringify, как в примере 2, в этом случае не нужен.