Логотип Workflow

Article

Updated at:

Json In Api

Stage 3. JSON in API

JSON в API нужно воспринимать как внешний договор между клиентом и сервером. Этот договор читают не только разработчики backend, но и frontend, мобильные приложения, автотесты, партнёрские интеграции и аналитика. Если договор неявный, даже маленькое изменение может сломать чужую часть системы. Поэтому JSON проектируют как стабильный интерфейс: с понятными полями, предсказуемыми типами и прозрачными правилами ошибок.

JSON serialization

1. Что такое JSON простыми словами

JSON — это текстовый формат данных с объектами {}, массивами [] и парами ключ: значение. Его главное преимущество в API: один и тот же payload одинаково понятен системам на Java, JavaScript, Python, Go и других языках. Клиенту не нужно знать внутреннее устройство сервера, ему нужно знать только структуру JSON-контракта.

Для старта важно не путать формат и смысл. Формат отвечает на вопрос «это корректный JSON-текст?». Смысл отвечает на вопрос «эти данные подходят бизнес-правилам API?». Например, строка "twenty" в поле age может быть корректной как JSON, но неверной по правилам вашего сервиса, если ожидается число.

2. Минимальные правила синтаксиса, которые чаще всего ломают запросы

  1. Ключи всегда в двойных кавычках: "email", а не email.
  2. Строки тоже в двойных кавычках: "Anna", а не 'Anna'.
  3. Запятая разделяет элементы, но не ставится после последнего поля.
  4. Типы должны совпадать с контрактом: число, строка, булево, массив, объект.
  5. null — это явное значение «пусто», а не «поле отсутствует».

3. Базовые типы JSON и как их читать в API

{
  "id": 42,
  "name": "Anna",
  "isActive": true,
  "tags": ["backend", "java"],
  "profile": {
    "city": "Kyiv"
  },
  "middleName": null
}
ТипПримерПрактический смысл
string"[email protected]"Текст, например email или имя
number27Числа для возраста, цены, количества
booleantrueФлаг включено/выключено
array["a", "b"]Список значений
object{"city":"Kyiv"}Группа связанных полей
nullnullЗначение явно отсутствует

4. Как JSON проходит через сервер

Чтобы новичку было проще отлаживать API, удобно помнить простой поток обработки:

flowchart LR
  A[HTTP Request with JSON] --> B[Parse JSON]
  B --> C[Validate Fields and Types]
  C --> D[Run Business Rules]
  D --> E[JSON Response or Error]

Если ошибка произошла на этапе парсинга, клиент получает ответ о неверном формате. Если парсинг успешный, но не пройдена валидация, клиент получает ошибку по конкретным полям. Если валидация прошла, запускается бизнес-логика. Такое разделение делает ответы API предсказуемыми и удобными для автоматической обработки.

5. Разделяйте внутренние модели и внешний контракт (DTO)

Внутри сервиса модели меняются часто: добавляются технические поля, меняется хранение, пересобираются связи. Внешний API должен меняться осторожно. Если отдавать внутренние сущности напрямую, любое внутреннее изменение превращается в риск для клиентов. DTO решают эту проблему: вы явно описываете, что именно доступно снаружи и какие поля являются частью договора.

6. Единый формат ошибок

{
  "error": "validation_failed",
  "fields": {
    "email": "must be valid"
  },
  "traceId": "d1f1c9a2"
}

Одинаковая структура ошибок нужна для всех endpoint-ов. Тогда frontend и mobile не пишут уникальную обработку под каждую ручку, а используют общий механизм: показать ошибку, подсветить поле, записать traceId для логов. Это ускоряет разработку и упрощает поддержку.

7. Дата и время: главное правило для интеграций

Самая частая скрытая проблема в API — разный формат времени в разных ответах. Один endpoint возвращает UTC, другой локальное время без timezone, третий строку в произвольном формате. В итоге отчёты по регионам расходятся, а фильтры «за последние 24 часа» работают по-разному. Для начинающего разработчика полезно зафиксировать правило сразу: используйте единый формат времени для всех endpoint-ов, обычно ISO 8601 в UTC.

8. Как безопасно развивать контракт

  1. Новые поля добавляйте как необязательные.
  2. Не меняйте тип существующего поля без миграции.
  3. Не удаляйте обязательные поля сразу, дайте переходный период.
  4. Фиксируйте версию API, если изменения потенциально несовместимы.

9. Проверочный список для новичка перед публикацией endpoint-а

  1. Все ли поля имеют понятные названия без знания внутреннего кода?
  2. Есть ли явные правила для обязательных и опциональных полей?
  3. Одинаков ли формат ошибок на всех ручках?
  4. Единообразен ли формат даты и времени?
  5. Есть ли тесты не только на успешный сценарий, но и на ошибки?

10. Как один и тот же JSON читается в Java и Python

Возьмем простой ответ API:

{
  "userId": 42,
  "email": "[email protected]",
  "active": true
}

В Java часто используют Jackson для чтения JSON в объект DTO. Так проще работать с типами и валидацией на уровне кода.

import com.fasterxml.jackson.databind.ObjectMapper;

public class JsonReadExample {
    static class UserDto {
        public int userId;
        public String email;
        public boolean active;
    }

    public static void main(String[] args) throws Exception {
        String json = "{\"userId\":42,\"email\":\"[email protected]\",\"active\":true}";
        ObjectMapper mapper = new ObjectMapper();
        UserDto user = mapper.readValue(json, UserDto.class);

        System.out.println(user.userId);   // 42
        System.out.println(user.email);    // [email protected]
        System.out.println(user.active);   // true
    }
}

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

import json

raw = '{"userId": 42, "email": "[email protected]", "active": true}'
data = json.loads(raw)

print(data["userId"])   # 42
print(data["email"])    # [email protected]
print(data["active"])   # True

Главная идея для новичка: JSON-контракт один и тот же, а способ чтения зависит от языка и библиотек. Поэтому стабильная структура полей важнее, чем конкретный стек клиента.

Практический сценарий

Команда добавила поле createdAt в локальном времени без timezone. На одном стенде всё выглядело правильно, но в отчётах по нескольким регионам данные «уехали». Выяснилось, что часть сервисов интерпретировала время как UTC, а часть как локальное. Ошибка была не в бизнес-логике, а в плохо заданном JSON-контракте. Если бы формат времени был заранее стандартизирован и описан для всех клиентов, инцидента можно было бы избежать.

Авторизуйтесь чтоб пройти тесты

Quiz

Проверьте, что вы усвоили

Practice

Интерактивная практика

Выполните задания и сразу проверьте ответ.