JSON Toolkit

Bez additionalProperties walidacja schematu nic nie sprawdza

Podsumowanie: Zdana walidacja nie oznacza czystych danych. Pydantic domyślnie ignoruje nieznane pola, Zod je usuwa, Ajv przepuszcza — zmyślone parametry i literówki przechodzą po cichu. Artykuł pokazuje trzy formy cichej akceptacji i daje pełne przepisy: zamykać obiekty, kontrolować koercję, zaciskać każdy poziom zagnieżdżenia.

Intermediate~8 min czytaniaOpublikowano 2026-11-02Zaktualizowano 2026-11-02
JSON z nadmiarowymi polami przechodzący walidację

Wniosek: domyślnie walidatory ignorują niezadeklarowane pola zamiast je odrzucać. Bez additionalProperties: false zdana walidacja dowodzi tylko, że zadeklarowane pola są w porządku.

Najniebezpieczniejsze zachowanie walidatora to nie błąd, lecz cisza. Literówka w kluczu lub parametr wymyślony przez model przechodzi przez walidację bezgłośnie i wybucha dopiero w logice biznesowej.

Jeden: walidacja, która „przechodzi"

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

Wyślij {"order_id": "A1", "amount": 50, "reasn_code": "damaged"} — trzeci klucz to literówka. Z domyślną konfiguracją Ajv wynik to sukces. Nadmiarowe pole nie jest ani odrzucone, ani oznaczone.

W specyfikacji JSON Schema domyślna wartość additionalProperties to true: niezadeklarowane pola są dozwolone.

Dwa: trzy odmiany ciszy

Runtime Domyślne zachowanie Skutek
Ajv (JS) przepuszcza brudne dane docierają do logiki
Zod z.object usuwa pole znika, obiekt się kurczy
Pydantic v2 ignoruje (extra="ignore") to samo, bez śladu w logach

Usuwanie jest skrytsze niż przepuszczenie. Obie biblioteki domyślnie zawodzą tak samo — po cichu.

Trzy: wywołania narzędzi LLM pogłębiają problem

Argumenty generuje model: wymyśla nazwy pól i przekazuje "3" jako liczbę. Platformy definiują parametry w JSON Schema, ale domyślnie nie wymuszają zamknięcia schematu — tryb strict trzeba włączyć jawnie, a ograniczenia gramatyczne obejmują tylko bezpośrednie wyjście modelu.

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

Przy zamkniętym obiekcie reason_code i urgent są odrzucane, a błąd wskazuje na /reason_code.

Cztery: jak zamknąć

Ajv: dodaj additionalProperties: false w węźle obiektu.

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 lub .strict(). Pydantic: ConfigDict(extra="forbid").

Wspólna reguła: zamykanie odbywa się na każdym poziomie. Każdy zagnieżdżony obiekt wymaga własnego additionalProperties: false.

Pięć: polityka koercji

Tryb lax Pydantic zamienia "5" na 5. Trzy polityki: ścisła (odrzucać złe typy), kontrolowana (tylko jawne, ograniczone konwersje), swobodna (tylko dane wewnętrzne). Dla niezaufanych wejść wybierz pierwszą lub drugą i zapisz ją w testach.

Sześć: lista kontrolna zagnieżdżenia

Punkt Działanie
Obiekt główny additionalProperties: false
Każdy zagnieżdżony obiekt to samo
Elementy tablic zamykać obiekty w items
Enumy i zakresy dodać enum, minimum/maximum
Wygenerowane schematy uzupełnić ręcznie

Siedem: po odrzuceniu

allErrors: true zgłasza wszystkie pola naraz; verbose: true dodaje ścieżki. Problemy składniowe łapie parser przed walidacją schematu.

FAQ

Za surowo?

Zależy od kontraktu. Dla własnych wejść zamykaj; dla rozszerzalnych danych zewnętrznych zamknij tylko rdzeń i wydziel obszar rozszerzeń.

Strip w Zodzie jest bezpieczniejszy?

Nie: chroni downstream kosztem wywołującego. Błędy powinny pojawiać się wcześnie i jawnie.

Czy strict mode platformy zastępuje walidację lokalną?

Nie. Sam schemat może być otwarty, a gramatyka może nie obejmować argumentów narzędzi.

Po zamknięciu stare dane masowo padają?

To dokładnie to, co trzeba było ujawnić. Zinwentaryzuj przez allErrors, dodaj nieszkodliwe pola, popraw szkodliwe.

Rozwiązanie w jednej linii?

Nie, ale minimalny krok: sprawdzić, czy za każdym type: "object" następuje additionalProperties: false.