Проверка схемы JSON Обнаружение нарушений API-соглашений до их отправки

Опубликовано

Проверка схемы JSON выявляет нарушения API-договоров на этапе разработки. Изучите основные ключевые слова, модуль AJV для Express, интеграцию с FastAPI, обнаружение отклонений схемы и связь с OpenAPI.

Проверка схем JSON: обнаружение нарушений API-договоров до их отправки 1
Реклама · УДАЛИТЬ?

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

В этом руководстве описано, как работает схема JSON, какие валидаторы использовать в Node.js, Python и AWS, а также как сохранять схему, чтобы она не отклонялась от реальности.

Что такое схема JSON

Схема JSON — это языковой набор для описания структуры документа JSON. Это не код — это метаданные. Вы пишете схему, которая объявляет, как должен выглядеть корректный объект JSON, а затем применяете валидатор к ней.

Сама схема — это документ JSON. Пример минимального варианта:

{
  "$schema": "https://json-schema.org/draft/2020-12",
  "type": "object",
  "properties": {
    "email": { "type": "string", "format": "email" },
    "age":   { "type": "integer", "minimum": 0 }
  },
  "required": ["email"]
}

Это всё. Подаёте это в валидатор, вводя любое тело JSON, и получаете проход или структурированный список ошибок.

Основные ключевые слова

Несколько ключевых слов покрывают большинство реальных потребностей валидации:

Ключевое слово Что проверяется Пример
type Тип значения "type": "string"
properties Формат полей объекта "properties": { "name": { "type": "string" } }
required Какие свойства должны присутствовать "required": ["email", "password"]
additionalProperties Разрешено ли присутствие неизвестных свойств "additionalProperties": false
enum Значение должно быть одним из фиксированного набора "enum": ["admin", "editor", "viewer"]
format Семантическая проверка формата "format": "email" или "format": "date-time"
pattern Строка должна соответствовать регулярному выражению "pattern": "^[a-z0-9-]+$"
$ref Ссылка на другую схему "$ref": "#/$defs/Address"

additionalProperties: false заслуживает особого внимания. Это ключевое слово, которое делает вашу схему строгой — любое свойство, не объявленное в properties вызывает ошибку валидации. По умолчанию оно отключено, что означает, что большинство схем безошибочно принимают "мусорные" поля, если вы не включили это явно.

Полная схема: запрос на регистрацию пользователя

Вот полная схема JSON для тела запроса на эндпоинт регистрации. Это тип схемы, которую вы пишете один раз и проверяете на каждом уровне, касающемся эндпоинта.

{
  "$schema": "https://json-schema.org/draft/2020-12",
  "title": "UserRegistration",
  "type": "object",
  "required": ["email", "password", "username"],
  "additionalProperties": false,
  "properties": {
    "email": {
      "type": "string",
      "format": "email"
    },
    "password": {
      "type": "string",
      "minLength": 8
    },
    "username": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9_]{3,32}$"
    },
    "role": {
      "type": "string",
      "enum": ["user", "admin"],
      "default": "user"
    },
    "birthDate": {
      "type": "string",
      "format": "date"
    }
  }
}

Вы можете протестировать это интерактивно с любым телом запроса с помощью IO Tools JSON Schema Validator до подключения к вашему коду базы.

Проверка тел запросов API

Express + AJV

AJV — самый быстрый валидатор JSON Schema для Node.js. Вот промежуточный слой для Express, который проверяет тело запроса до того, как он достигнет обработчика: предупреждает AJV о сборе всех ошибок в документе, а не остановке на первой — полезно, когда вы хотите вернуть все ошибки валидации клиенту сразу.

import Ajv from "ajv";
import addFormats from "ajv-formats";

const ajv = new Ajv({ allErrors: true });
addFormats(ajv);

function validateBody(schema) {
  const validate = ajv.compile(schema);
  return (req, res, next) => {
    if (validate(req.body)) {
      return next();
    }
    res.status(400).json({
      error: "Validation failed",
      details: validate.errors,
    });
  };
}

// Usage
app.post("/register", validateBody(registrationSchema), registerHandler);

allErrors: true В Python FastAPI использует Pydantic, и автоматически генерирует схему JSON из аннотаций типов. Если вы работаете с сырой схемой JSON из внешнего источника, а не с моделями Pydantic,

FastAPI (Python)

это стандартная библиотека: jsonschema AWS API Gateway

from jsonschema import validate, ValidationError

schema = { ... }  # your schema dict

try:
    validate(instance=request_body, schema=schema)
except ValidationError as e:
    return {"error": e.message}, 400

API Gateway поддерживает валидацию тела запроса встроенными средствами. Вы определяете модель (это документ JSON Schema) и привязываете её к методу как

валидатор. Запросы, не прошедшие валидацию, отклоняются на уровне гейтвей — до того, как ваша Lambda-функция даже запустится. Это устраняет целый класс ошибок обработчиков и уменьшает количество вызовов при холодном запуске для невалидного трафика. REQUEST_BODY Разделяемые схемы с помощью

Когда несколько схем имеют общую структуру — например, адрес, денежную сумму или объект пагинации — определяйте её один раз в $ref и $defs

и ссылайтесь на неё с помощью $defs Для больших проектов схемы хранятся в отдельных файлах и $ref:

{
  "$defs": {
    "Address": {
      "type": "object",
      "required": ["street", "city", "country"],
      "properties": {
        "street": { "type": "string" },
        "city":   { "type": "string" },
        "country": { "type": "string", "pattern": "^[A-Z]{2}$" }
      }
    }
  },
  "type": "object",
  "properties": {
    "billingAddress":  { "$ref": "#/$defs/Address" },
    "shippingAddress": { "$ref": "#/$defs/Address" }
  }
}

указывает на URI. Валидаторы, поддерживающие ключевое слово $ref и разрешение URI, могут загружать схемы лениво или из реестра — AJV обрабатывает это через $id Смещение схемы addSchema().

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

Симптомы незаметны. Поле переименовано в коде, но не в схеме — валидация всё ещё проходит, потому что

не установлена в значение false. Обязательное поле становится необязательным в реальности, потому что в коде больше не проверяется — схема всё ещё требует его, но никто не замечает, пока клиент не отправит запрос без него. additionalProperties Обнаружение смещения требует рассматривать валидацию схемы как тест, а не как проверку на этапе выполнения. Некоторые команды автоматизируют это с помощью тестов на "снимки" по реальным фиксированным ответам. Другие запускают валидатор схемы в CI на наборе захваченных запросов API. Главное — чтобы схема регулярно проверялась, а не просто размещалась один раз.

JSON Schema и OpenAPI

OpenAPI (ранее Swagger) использует JSON Schema для описания тел запросов и ответов, но с некоторыми изменениями. В более ранних версиях (OpenAPI 2.0, 3.0) использовался подмножество JSON Schema с расширениями. OpenAPI 3.1 лучше соответствует JSON Schema draft 2020-12, поэтому схемы почти полностью взаимозаменяемы.

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

Генерация схем из существующих данных

Писание схем вручную работает хорошо для новых API. Для существующих API с неподocumented поведением чаще всего удобнее сгенерировать схему из реальных тел и затем усилить её.

(Python) и

Инструменты, такие как genson (Node.js) берут образцы JSON-объектов и генерируют черновую схему. Полученная схема почти всегда слишком расслаблена — всё становится необязательным, нет generate-schema — но это дает вам стартовую точку. Вы затем добавляете additionalProperties: false , ужесточаете requiredопределения и добавляете type ограничения, где значения ограничены. enum Этот подход также помогает при интеграции с внешним API, где нет документации по схеме. Запускайте несколько ответов через генератор схем, объединяйте результаты, и у вас получится рабочий контракт для проверки.

Проверка схемы JSON должна быть на каждом уровне, где обрабатывается структурированные данные — в HTTP-миддлваре, потребителях очередей сообщений, путях записи в базу данных. Чем раньше обнаруживается нарушение соглашения, тем дешевле его исправление. Инструмент для проверки схемы JSON можно использовать для прототипирования схемы с реальными телами запросов до того, как вы решите интегрироваться с библиотекой, что делает это правильным первым шагом при работе с валидацией.


Проверка схемы JSON: обнаружение нарушений соглашения API до того, как они поступят 2 Проверка схемы JSON: обнаружение нарушений соглашения API до того, как они поступят 1 позволяет прототипировать схемы в отношении реальных данных до того, как вы будете привязаны к интеграции с библиотекой, что делает это правильным первым шагом для любой работы по проверке.

Хотите убрать рекламу? Откажитесь от рекламы сегодня

Установите наши расширения

Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска

в Расширение Chrome в Расширение края в Расширение Firefox в Расширение Opera

Табло результатов прибыло!

Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!

Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?
Реклама · УДАЛИТЬ?

новости с техническими моментами

Примите участие

Помогите нам продолжать предоставлять ценные бесплатные инструменты

Купи мне кофе
Реклама · УДАЛИТЬ?