JSON Toolkit

Без additionalProperties перевірка схеми нічого не перевіряє

Головне: Успішна перевірка не означає чисті дані. Pydantic типово ігнорує невідомі поля, Zod їх вилучає, Ajv пропускає — вигадані параметри й одруківки проходять тихо. Стаття показує три форми мовчазного прийняття та дає повні рецепти: закривати об'єкти, контролювати приведення типів, підтягувати кожен рівень вкладеності.

Intermediate~8 хв читанняОпубліковано 2026-11-02Оновлено 2026-11-02
JSON із зайвими полями проходить перевірку

Висновок: типово валідатори ігнорують незаявлені поля, а не відхиляють їх. Без additionalProperties: false успішна перевірка лише підтверджує, що заявлені поля в порядку.

Найнебезпечніша поведінка валідатора — не помилка, а тиша. Одруківка в ключі або вигаданий моделью параметр проходить крізь валідацію беззвучно й вибухає у бізнес-логіці.

Один: перевірка, що «пройшла»

{
  "type": "object",
  "properties": {
    "order_id": { "type": "string" },
    "amount": { "type": "number" }
  },
  "required": ["order_id", "amount"]
}

Передайте {"order_id": "A1", "amount": 50, "reasn_code": "damaged"} — третій ключ є одруківкою. Ajv з типовими налаштуваннями дає прохід. Зайве поле ніде не з'являється у помилках.

У специфікації JSON Schema значення additionalProperties типово true: незаявлені поля дозволені. Ви заявили «які поля є», але не «тільки ці поля можуть бути».

Два: три варіанти мовчання

Середовище Типова поведінка Наслідок
Ajv (JS) пропускає брудні дані потрапляють у логіку
Zod z.object вилучає поле зникає, об'єкт коротшає
Pydantic v2 ігнорує (extra="ignore") те саме, без сліду в журналах

Вилучення прихованіше за пропуск. Обидві бібліотеки з коробки мовчки провалюються однаково.

Три: виклики інструментів LLM загострюють проблему

Аргументи інструментів генерує модель: вона впевнено вигадує назви полів і передає "3" замість числа. Платформи визначають параметри через JSON Schema, але типово не змушують схему бути закритою — strict-режим треба вмикати явно, а граматичні обмеження стосуються лише прямого виводу моделі.

{
  "order_id": 4411,
  "refund_amount_usd": 50,
  "reason_code": "damaged",
  "urgent": "yes"
}

Без закриття об'єкта зайві ключі проходять; після закриття їх відхилено, і помилка вказує на /reason_code.

Чотири: як закрити

Ajv: додайте additionalProperties: false на вузол об'єкта.

import Ajv from "ajv";
const ajv = new Ajv({ allErrors: true });

const schema = {
  type: "object",
  properties: { order_id: { type: "string" }, amount: { type: "number" } },
  required: ["order_id", "amount"],
  additionalProperties: false,
};

const validate = ajv.compile(schema);
validate({ order_id: "A1", amount: 50, reasn_code: "x" }); // false

Zod: z.strictObject або .strict(). Pydantic: ConfigDict(extra="forbid").

Спільне правило: закриття на кожному рівні. Кожен вкладений об'єкт потребує власного additionalProperties: false.

П'ять: політика приведення типів

Pydantic у lax-режимі перетворює "5" на 5. Три політики: сувора (відхиляти невідповідні типи), контрольована (тільки явні перетворення з межами), повністю вільна (лише для внутрішніх даних). Для ненадійних входів обирайте першу або другу й фіксуйте в тестах.

Шість: чекліст вкладеності

Точка Дія
Верхній об'єкт additionalProperties: false
Кожен вкладений object те саме
Елементи масивів закривати об'єкти в items
Enum і діапазони додати enum, minimum/maximum
Згенеровані схеми доповнювати вручну

Сім: після відхилення

allErrors: true показує всі поля одразу, verbose: true додає шляхи. Синтаксичні проблеми має ловити парсер до перевірки схеми.

FAQ

Чи не надто суворо?

Залежить від контракту. Для власних входів — закривати; для сторонніх даних з розширеннями — лише ядро.

Zod strip безпечніший?

Ні: він захищає нижні шари, але викликач не знає про втрату поля. Помилки мають з'являтися рано й явно.

strict-режим платформи замінює локальну перевірку?

Ні. Схема може бути відкритою, а граматика може не покривати аргументи інструментів.

Після закриття старі дані масово падають?

Це і є проблема, яку треба показати. Інвентаризуйте через allErrors, додайте нешкідливі поля, виправте шкідливі.

Однорядкове рішення?

Ні, але мінімальний крок: перевірити, що кожен type: "object" супроводжується additionalProperties: false.