Skip to content
Powrót do bloga
Poradniki

Walidacja JSON Schema w 2026: przewodnik Ajv, Python i przeglądarka

Waliduj JSON względem schematu w Node, Pythonie i przeglądarce. Funkcje Draft 2020-12, realne wzorce API i gotowe do skopiowania przykłady. Wypróbuj za darmo.

12 min czytania

Walidacja JSON Schema: walidacja JSON w Node, Pythonie i przeglądarce (2026)

JSON Schema to kontrakt dla danych JSON. Deklaruje się typy pól, klucze wymagane i ograniczenia, a walidator sprawdza, czy dokument spełnia ten kontrakt. W Node po najszybszą walidację sięga się po Ajv, w Pythonie po bibliotekę jsonschema z przenośnymi schematami, a w przeglądarce wystarczy dołączyć Ajv do bundla, żeby formularze i konfigi reagowały natychmiast. Dla nowych projektów w 2026 roku wybiera się Draft 2020-12.

Niżej znajdziesz najmniejszy działający przykład, kompletne wzorce w trzech środowiskach uruchomieniowych oraz typowe pułapki, które prowadzą do sytuacji „walidacja przechodzi, ale produkcja odrzuca dane”.

Czym jest JSON Schema (a czym nie jest)

Definicja jednym zdaniem

JSON Schema to dokument JSON, który opisuje kształt innych dokumentów JSON. Walidator czyta schemat oraz dane, a następnie potwierdza zgodność lub zwraca ścieżki, w których walidacja się nie powiodła.

Najmniejszy użyteczny przykład:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": { "name": { "type": "string" } },
  "required": ["name"]
}

{"name": "Alice"} przechodzi. {"age": 30} nie przechodzi (brak name). {"name": 42} nie przechodzi (name nie jest typu string). To jest cały model mentalny.

JSON Schema a walidacja składni JSON

To dwa różne problemy, często mylone ze sobą.

WymiarSprawdzenie składni JSONWalidacja JSON Schema
Co sprawdzaCzy to jest poprawny dokument JSON?Czy ten JSON pasuje do kontraktu?
WykrywaBrakujące przecinki, pojedyncze cudzysłowy, komentarzeNiewłaściwe typy, brakujące pola wymagane, wartości spoza zakresu
NarzędziaJSON.parse(), Formatowanie JSON onlineAjv, jsonschema (Python), fastjsonschema
Kiedy po nie sięgnąćNajpierw, przed parsowaniemTuż po parsowaniu, przed logiką biznesową

W praktyce robi się oba kroki: najpierw sformatować payload w Formatowaniu JSON online, żeby potwierdzić, że się parsuje, a potem puścić go przez schemat dla zgodności z kontraktem.

JSON Schema a JSONPath, JSON Patch, jq i TypeScript

Pięć narzędzi dzieli tę przestrzeń problemów. Macierz decyzyjna:

NarzędziePytanie, na które odpowiadaKiedy po nie sięgnąć
JSON SchemaCzy ten JSON pasuje do oczekiwanej struktury?Walidacja wejścia API, plików konfiguracyjnych, payloadów formularzy
JSONPathJak wyciągnąć wartość z tego JSON?Wyciąganie zagnieżdżonych pól, masowe odczyty
JSON Patch (RFC 6902)Jak opisać różnicę z A do B?Edycja współdzielona, przyrostowa synchronizacja
jqJak przetwarzać JSON w wierszu poleceń?Skrypty powłoki, potoki logów, kontrole CI
Typy TypeScriptCzy mój kod używa tego kształtu poprawnie?Gwarancje na etapie kompilacji w obrębie jednej bazy kodu

Podział wygląda tak: JSON Schema waliduje nieznane dane w czasie wykonania, TypeScript waliduje znany kod w czasie kompilacji. TypeScript nie pomoże z JSON-em z webhooka strony trzeciej ani z payloadem wklejonym przez użytkownika; od tego jest właśnie JSON Schema. Zod i Pydantic zajmują pozycję pośrednią (typy w czasie kompilacji plus walidacja w czasie wykonania), o czym niżej.

JSON Schema a OpenAPI

Częste nieporozumienie głosi, że OpenAPI zastępuje JSON Schema. Tak nie jest. OpenAPI używa JSON Schema wewnątrz do opisu ciał żądań i odpowiedzi, a na to nakłada ścieżki, parametry, schematy zabezpieczeń oraz adresy serwerów. Schemat to kontrakt kształtu danych; OpenAPI to kontrakt API, który go opakowuje.

WymiarJSON SchemaOpenAPI
ZakresKształt jednego dokumentu JSONKształt całego API HTTP
ZależnościBrak (schemat to samowystarczalny JSON)Importuje JSON Schema do definicji ciał
Sparowanie wersjiDraft 7 / Draft 2019-09 / Draft 2020-12OpenAPI 3.0 używa podzbioru Draft 4; OpenAPI 3.1 używa Draft 2020-12 natywnie
Typowe zastosowaniePliki konfiguracyjne, koperty wiadomości, walidacja formularzy, kontrakty pojedynczych payloadówProjektowanie REST API, generowanie SDK, mock serwery, testy kontraktowe
Generowanie koduOgraniczone (kilka narzędzi w stylu quicktype)Dojrzały ekosystem (openapi-generator, oapi-codegen, SDK dostawców)
Zarządzanie kontraktemJeden plik na kształt, bez routinguŚcieżki, operacje, przepływy autoryzacji, wersjonowane endpointy w jednym dokumencie

Po sam JSON Schema sięga się wtedy, gdy artefakt to pojedynczy dokument: payload webhooka, plik konfiguracyjny, wiadomość kolejki albo formularz. Nie ma powierzchni HTTP do opisania, więc OpenAPI to narzut.

Po OpenAPI sięga się wtedy, gdy publikujesz API HTTP i chcesz mieć jeden dokument napędzający dokumentację, generowanie SDK, mock serwery i testy kontraktowe. Schematy najpierw definiuje się jako samodzielne pliki JSON Schema w katalogu schemas/, a następnie podpina przez $ref z dokumentu OpenAPI. Schematy zostają wtedy używalne także poza kontekstem API.

Sparowanie wersji potrafi zmylić zespoły. OpenAPI 3.0 używa podzbioru Draft 4, więc słów kluczowych Draft 2020-12, takich jak prefixItems czy unevaluatedProperties, nie da się użyć w dokumencie 3.0 — generatory zignorują je po cichu. OpenAPI 3.1 jest nadzbiorem Draft 2020-12, więc cokolwiek poprawne w 2020-12 jest poprawne w 3.1. Jeżeli wybór jest po twojej stronie, celuj w OpenAPI 3.1 i wszędzie pisz schematy w Draft 2020-12.

Pierwszy JSON Schema (5 minut)

Słowa kluczowe na początek

Te wystarczą do pokrycia 80% przypadków:

{
  "type": "object",
  "properties": {
    "id":       { "type": "integer", "minimum": 1 },
    "email":    { "type": "string", "format": "email" },
    "age":      { "type": "integer", "minimum": 0, "maximum": 150 },
    "tags":     { "type": "array", "items": { "type": "string" }, "minItems": 1 },
    "role":     { "enum": ["admin", "editor", "viewer"] },
    "metadata": { "type": "object", "additionalProperties": true }
  },
  "required": ["id", "email"],
  "additionalProperties": false
}

Słownictwo:

  • typestring, number, integer, boolean, null, array, object
  • properties + required — deklaruje pola i oznacza, które muszą wystąpić
  • enum / const — ogranicza do ustalonego zbioru lub jednego literału
  • minimum / maximum / multipleOf — ograniczenia liczbowe
  • minLength / maxLength / pattern — długość ciągu i wyrażenie regularne
  • minItems / maxItems / uniqueItems — kształt tablicy
  • additionalProperties: false odrzuca niezadeklarowane klucze (zawsze ustaw to w kontraktach wejściowych)

Przykłady JSON Schema według zastosowania

Powyższe słowa kluczowe pojawiają się w różnych kombinacjach w zależności od tego, co walidujesz. Kilka reprezentatywnych kształtów:

Ciało żądania API — endpoint rejestracji przyjmujący email i hasło:

{
  "type": "object",
  "properties": {
    "email":    { "type": "string", "format": "email" },
    "password": { "type": "string", "minLength": 8, "maxLength": 128 }
  },
  "required": ["email", "password"],
  "additionalProperties": false
}

Plik konfiguracyjny — konfiguracja loggera, która domyka poziom do ustalonego zbioru:

{
  "type": "object",
  "properties": {
    "level":  { "enum": ["debug", "info", "warn", "error"] },
    "output": { "type": "string", "default": "stdout" }
  },
  "required": ["level"],
  "additionalProperties": false
}

Payload formularza z regułami warunkowymi — gdy accountType ma wartość "business", taxId staje się wymagane:

{
  "type": "object",
  "properties": {
    "accountType": { "enum": ["personal", "business"] },
    "taxId":       { "type": "string" }
  },
  "if":   { "properties": { "accountType": { "const": "business" } } },
  "then": { "required": ["taxId"] }
}

Rekord JSON pochodzący z wiersza CSV — jeden wiersz wyeksportowanej tabeli zamówień:

{
  "type": "object",
  "properties": {
    "orderId":   { "type": "string", "pattern": "^ORD-[0-9]{6}$" },
    "orderedOn": { "type": "string", "format": "date" },
    "totalUsd":  { "type": "number", "minimum": 0 }
  },
  "required": ["orderId", "orderedOn", "totalUsd"]
}

Koperta zdarzenia webhooka — oneOf rozróżnia po literale type, więc każdy wariant zdarzenia ma własny kształt payloadu:

{
  "oneOf": [
    { "properties": { "type": { "const": "order.created" }, "data": { "$ref": "#/$defs/order" } } },
    { "properties": { "type": { "const": "order.refunded" }, "data": { "$ref": "#/$defs/refund" } } }
  ]
}

Te pięć przykładów pokrywa większość tego, co zespoły piszą w praktyce. Skopiuj najbliższe dopasowanie i dostosuj nazwy pól — słownictwo słów kluczowych pozostaje to samo.

Walidacja bez instalowania czegokolwiek

Wklej schemat i payload do playgroundu na ajv.js.org lub jsonschemavalidator.net i dostaniesz natychmiastowy werdykt. Jeśli sam JSON wygląda podejrzanie, najpierw przepuść go przez Formatowanie JSON online.

Walidacja w Node.js z Ajv

Instalacja i przykład w 12 wierszach

Ajv kompiluje schemat do zoptymalizowanej funkcji przy pierwszym wywołaniu compile, a następnie ją ponownie wykorzystuje.

npm install ajv
import Ajv from "ajv";
const ajv = new Ajv();

const schema = {
  type: "object",
  properties: {
    name: { type: "string" },
    age:  { type: "integer", minimum: 0 }
  },
  required: ["name"]
};

const validate = ajv.compile(schema);
const data = { name: "Alice", age: 30 };

if (!validate(data)) console.log(validate.errors);
else                  console.log("OK");

Przełączenie na Draft 2020-12

Domyślny konstruktor Ajv jest nadal przypięty do Draft 7 ze względu na zgodność wsteczną. Draft 2020-12 wybiera się jawnie:

import Ajv2020 from "ajv/dist/2020";
const ajv = new Ajv2020({ strict: true, allErrors: true });

Teraz dostępne są prefixItems, unevaluatedProperties i $dynamicRef. Działanie każdego z nich opisuje sekcja o Draft 2020-12 niżej.

Włączenie walidacji format

Pułapka, na którą nabiera się więcej programistów niż na jakąkolwiek inną osobliwość Ajv: format: "email" domyślnie nic nie robi. Specyfikacja traktuje format jako wskazówkę, więc trzeba zarejestrować moduł formatów:

npm install ajv-formats
import addFormats from "ajv-formats";
addFormats(ajv);  // teraz "format": "email" rzeczywiście waliduje

Bez tego kroku {"email": "not-an-email"} przechodzi schemat wymagający format: "email". Na produkcji ajv-formats instaluje się zawsze.

Middleware Express na poważnie

Jeden walidator na trasę, skompilowany przy starcie:

import express from "express";
import Ajv2020 from "ajv/dist/2020";
import addFormats from "ajv-formats";

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

const validateUser = ajv.compile({
  type: "object",
  properties: {
    email: { type: "string", format: "email" },
    age:   { type: "integer", minimum: 13 }
  },
  required: ["email"],
  additionalProperties: false
});

const app = express();
app.use(express.json());

app.post("/users", (req, res) => {
  if (!validateUser(req.body)) {
    return res.status(400).json({ errors: validateUser.errors });
  }
  // ... logika biznesowa
  res.status(201).json({ ok: true });
});

Najdroższy pojedynczy błąd: wywoływanie ajv.compile(schema) wewnątrz handlera żądania. Skompiluj raz w zakresie modułu i ponownie używaj zwróconej funkcji. Rekompilacja przy każdym żądaniu obniża przepustowość pięćdziesięciokrotnie lub bardziej.

Walidacja w Pythonie z jsonschema

Instalacja i podstawowe użycie

pip install jsonschema
from jsonschema import validate, ValidationError

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age":  {"type": "integer", "minimum": 0}
    },
    "required": ["name"]
}

try:
    validate(instance={"name": "Alice", "age": 30}, schema=schema)
    print("OK")
except ValidationError as e:
    print("FAIL:", e.message, "at", list(e.absolute_path))

Zbieranie wszystkich błędów z Draft202012Validator

validate() rzuca wyjątek przy pierwszym błędzie. Żeby wylistować wszystkie problemy naraz (przydatne przy odpowiedziach formularzy), użyj iter_errors:

from jsonschema import Draft202012Validator

validator = Draft202012Validator(schema)
errors = sorted(validator.iter_errors(instance), key=lambda e: e.path)
for err in errors:
    print(f"  - {'/'.join(map(str, err.absolute_path))}: {err.message}")

Teraz użytkownik poprawia wszystko naraz, zamiast wracać do formularza po każdym kolejnym błędzie.

jsonschema a Pydantic: kiedy co wybrać

Dwie solidne biblioteki Pythona, dwa różne problemy.

WymiarjsonschemaPydantic v2
Format schematuSłownik JSON (schemat to dane)Klasa Pythona z adnotacjami typów
WydajnośćInterpretowany, ~10–100× wolniejszy od PydanticRdzeń w Rust, najszybszy w ekosystemie
Przenośność między językamiTak (ten sam schemat działa w JS, Go, Rust)Nie (tylko Python)
Integracja z FastAPI / natywnymi modelamiKonwersja ręcznaWbudowana
Pełne słowa kluczowe Draft 2020-12 ($dynamicRef itp.)KompletneCzęściowe

Reguła, która sprawdza się na produkcji: jsonschema do kontraktów między językami (OpenAPI, publiczne API, webhooki) i Pydantic do wewnętrznych usług w Pythonie. Wiele zespołów stosuje obie: jsonschema na bramie do egzekwowania kontraktu, Pydantic w warstwie aplikacji do typowanej logiki biznesowej. Schemat pozostaje przenośnym artefaktem, identycznym z tym, którym zasilisz Ajv.

Walidacja w przeglądarce

Po co w ogóle walidować po stronie klienta

Powody, w kolejności wagi:

  1. UX — natychmiastowa informacja zwrotna podczas pisania bije roundtripem do serwera na głowę.
  2. Pasmo — oczywiste błędy nigdy nie opuszczają przeglądarki.
  3. Higiena bezpieczeństwa — mniej śmieci dochodzi do backendu (co nie zastępuje walidacji serwerowej).

Nigdy nie należy polegać wyłącznie na walidacji po stronie klienta. Walidacja na serwerze zostaje obowiązkowa.

Bundlowanie Ajv do przeglądarki

npm install ajv ajv-formats
import Ajv2020 from "ajv/dist/2020";
import addFormats from "ajv-formats";

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

export const validateForm = ajv.compile({
  type: "object",
  properties: {
    email:    { type: "string", format: "email" },
    password: { type: "string", minLength: 8 }
  },
  required: ["email", "password"]
});

Bundle dorzuca około 30 KB po gzipie. Zauważalne, ale nie katastrofalne. Zespoły dostarczają Ajv wtedy, gdy zależy im na jednej definicji schematu współdzielonej między serwerem i klientem.

Lżejsze alternatywy: Zod i Valibot

Jeśli ekosystem JSON Schema nie jest potrzebny, a piszesz już w TypeScript, walidator natywny dla TS daje mniejsze bundle i ściślejszą inferencję typów:

import { z } from "zod";
const UserSchema = z.object({
  email: z.string().email(),
  password: z.string().min(8)
});
const result = UserSchema.safeParse(data);
if (!result.success) console.log(result.error.issues);

Valibot waży około 3 KB po gzipie i ma podobne API. Sprawdza się wtedy, gdy decyduje rozmiar bundla. Haczyk: żadna z tych bibliotek nie produkuje JSON Schema. Jeśli potrzebne jest jedno źródło prawdy współdzielone z backendami, klientami stron trzecich albo generatorami OpenAPI, zostań przy Ajv. Jeśli wszystko żyje wewnątrz własnego kodu TypeScript, Zod i Valibot okażą się wygodniejsze.

Co dodaje Draft 2020-12

prefixItems do walidacji krotek

Draft 7 wyrażał krotki przez items: [] plus additionalItems. Draft 2020-12 rozdziela je czysto:

{
  "type": "array",
  "prefixItems": [
    { "type": "string" },
    { "type": "number" }
  ],
  "items": false
}

["x", 42] przechodzi. ["x", 42, "extra"] nie przechodzi. Czyta się to tak samo, jak działa.

unevaluatedProperties dla schematów złożonych

Subtelny błąd, który dopada każdy zespół używający allOf albo oneOf: additionalProperties: false sprawdza tylko ten poziom, na którym się pojawia. Sąsiednie podschematy w allOf deklarują dowolne właściwości. Poprawka w 2020-12 to unevaluatedProperties: false:

{
  "allOf": [
    { "$ref": "#/$defs/base" }
  ],
  "unevaluatedProperties": false
}

To odrzuca każdą właściwość niewyewaluowaną przez żadną gałąź — zachowanie, którego większość programistów spodziewa się po additionalProperties: false.

$dynamicRef dla schematów rekurencyjnych

Każdy, kto próbował zadeklarować rekurencyjny schemat drzewa w Draft 7, zna akrobatykę z tym związaną. $dynamicRef razem z $dynamicAnchor porządkuje sprawę:

{
  "$dynamicAnchor": "node",
  "type": "object",
  "properties": {
    "value": { "type": "string" },
    "children": { "type": "array", "items": { "$dynamicRef": "#node" } }
  }
}

Rekurencja jest deklaratywna, a podtypy mogą ją nadpisywać bez przepisywania $id.

Draft 7 a 2020-12: co wybrać

  • Nowy projekt, nowoczesny zestaw narzędzi → Draft 2020-12.
  • Budowa lub konsumpcja OpenAPI 3.1 → 2020-12 jest tu natywnym dialektem.
  • Praca z OpenAPI 3.0 albo starszymi usługami → Draft 4 (OpenAPI 3.0 używa podzbioru Draft 4; nie miksuj dialektów).
  • Potrzebna szeroka kompatybilność walidatorów (Postman, starsze narzędzia CI) → Draft 7 dalej pozostaje najbezpieczniejszym formatem wymiany.

Każdy nowoczesny walidator (Ajv, pythonowy jsonschema, jsonschema-rs, javowy networknt/json-schema-validator) dziś wspiera 2020-12.

Wzorce z prawdziwego świata

Walidacja wejścia API

Middleware Express powyżej to kształt produkcyjny. Dwie praktyki dorzucam ponad to: schematy trzyma się w katalogu schemas/ w głównym folderze repozytorium, a w CI dodaje się krok uruchamiający ajv test (lub odpowiednik w Pythonie), żeby walidować same schematy względem meta-schematu JSON Schema.

Pliki konfiguracyjne

Visual Studio Code dostarcza integrację ze SchemaStore: autouzupełnianie i walidacja inline dla package.json, tsconfig.json i kilkudziesięciu innych. Dodaj pole $schema do własnych konfigów, a użytkownicy edytora dostaną to samo wsparcie.

Fixture’y testowe w CI

Fixture’y testowe gniją. Ktoś aktualizuje model, fixture zostaje w starym kształcie, test wciąż przechodzi, bo asercje nigdy nie dotknęły zmienionego pola. Łapie się to kontrolą schematu przed uruchomieniem asercji:

import { glob } from "glob";
const files = await glob("__tests__/fixtures/*.json");
for (const f of files) {
  const data = JSON.parse(await fs.readFile(f, "utf8"));
  if (!validate(data)) throw new Error(`${f}: ${ajv.errorsText(validate.errors)}`);
}

Gdy kontrola schematu zadziała, kolejnym krokiem jest zwykle porównanie strukturalne. Wciągnij fixture do Porównania JSON Online względem świeżej próbki produkcyjnej i zobacz, co się rozjechało. Jeśli w różnicy dominują znaczniki czasu i identyfikatory, sięgnij po wzorce ignorowania ścieżek snapshotów z przewodnika po JSON Diff i oddziel sygnał od szumu.

Payloady webhooków (Stripe, GitHub)

Webhooki stron trzecich to jedno z miejsc o najwyższej wartości dla zastosowania JSON Schema. Webhook to kontrakt; dostawca może go zmienić; sensownie być pierwszym, który to zauważy. Stripe i GitHub publikują opisy OpenAPI, z których wyciąga się schematy JSON. Walidacja nadchodzących zdarzeń sprawia, że zmiana łamiąca kompatybilność zapala się w monitoringu, a nie po cichu psuje stan.

Walidacja formularzy oparta na schemacie

React Hook Form ma adapter @hookform/resolvers/ajv, a Vue VeeValidate ma równoważną wtyczkę Ajv. Oba sterują renderowaniem formularzy, komunikatami błędów i walidacją wysyłki z jednego JSON Schema. Schemat zostaje jedynym źródłem prawdy, a UI dziedziczy jego reguły.

Przyjazne komunikaty błędów

Dlaczego domyślne są surowe

Z pudełka Ajv produkuje błędy w stylu #/properties/email format must match "email". Dla inżyniera debugującego 400 to wystarcza. Dla użytkownika wypełniającego formularz checkout zostaje bezużyteczne.

ajv-errors dla niestandardowych komunikatów

npm install ajv-errors
import ajvErrors from "ajv-errors";
ajvErrors(ajv);

const schema = {
  type: "object",
  properties: { email: { type: "string", format: "email" } },
  required: ["email"],
  errorMessage: {
    properties: { email: "Podaj prawidłowy adres email" },
    required: { email: "Email jest wymagany" }
  }
};

Słowo kluczowe errorMessage zostaje wewnątrz schematu, więc reguły walidacji i tekst widoczny dla użytkownika podróżują razem.

ajv-i18n dla przetłumaczonych błędów

ajv-i18n dostarcza tłumaczenia domyślnych komunikatów w ponad trzydziestu językach. Jedna linia przy starcie i walidator zaczyna mówić po hiszpańsku, francusku albo japońsku — w którymkolwiek języku obsługiwanym przez aplikację. Pasuje jako fallback, gdy nadpisania errorMessage nie pokrywają każdego ograniczenia.

Mapowanie ścieżek schematu na pola formularza

Każdy błąd Ajv ma instancePath w stylu /users/0/email. Większość bibliotek formularzy oczekuje ścieżek z kropkami w stylu users[0].email. Jednowierszowiec załatwia konwersję:

const fieldPath = error.instancePath.replace(/^\//, "").replace(/\//g, ".");

W pythonowym jsonschema odpowiednikiem jest error.absolute_path. Połącz po . i masz ten sam efekt.

Pięć pułapek, które przechodzą walidację, a potem wywalają produkcję

1. format jest domyślnie tylko wskazówką

Bez ajv-formats razem z addFormats(ajv) każde słowo kluczowe format to no-op. {"format": "email"} przyjmuje "not-an-email". Na produkcji pakiet formatów instaluje się zawsze.

2. additionalProperties domyślnie ma wartość true

Bez additionalProperties: false schemat akceptuje każde niezadeklarowane pole. Klienci mogą wysyłać dodatkowe pola, które całkowicie omijają walidację. Domyślnie w kontraktach wejściowych ustawia się additionalProperties: false; rozluźnia się to świadomie, jeśli faktycznie trzeba.

3. additionalProperties się nie komponuje

Wewnątrz allOf, oneOf albo anyOf, additionalProperties: false sprawdza tylko właściwości na własnym poziomie. Sąsiednie podschematy się prześlizgują. Poprawką w Draft 2020-12 jest unevaluatedProperties: false.

4. Zdalny $ref to ryzyko produkcyjne

$ref: "https://example.com/schema.json" sprawia, że Ajv pobiera plik przez sieć przy pierwszej kompilacji. Oznacza to opóźnienie, ekspozycję na DoS, jeśli zdalny host się zatnie, oraz powierzchnię ataku MITM. Wszystkie cele $ref warto trzymać inline albo ładować z dysku w czasie budowania.

5. Wygenerowane schematy odpływają od rzeczywistych danych

Narzędzia takie jak quicktype i typescript-json-schema generują schematy z istniejących typów. Wynik wychodzi zwykle zbyt liberalny: każde pole opcjonalne, additionalProperties otwarte. Wygenerowane schematy traktuje się jak szkice, dociska ręcznie i uruchamia CI walidujące rzeczywiste próbki produkcyjne względem schematu (i odwrotnie), żeby rozjazd ujawnił się szybko.

Wydajność: liczby i reguły kciuka

  • Ajv (Node.js): skompilowane walidatory załatwiają jedno sprawdzenie znacznie poniżej mikrosekundy. Najszybszy walidator JS klasy produkcyjnej.
  • jsonschema (Python): interpretowany, 10–100× wolniejszy od Pydantic. Gdy zaczyna boleć, wymień na fastjsonschema, który generuje kod Pythona i ląduje blisko Ajv.
  • Rust i Go: jsonschema-rs i xeipuuv/gojsonschema dają kolejne 2–5× nad Ajv na poziomie bramy.
  • Największy pojedynczy zysk to prekompilacja. ajv.compile(schema) raz przy ładowaniu modułu, ponowne użycie zwróconego walidatora przy każdym żądaniu. Rekompilacja przy każdym żądaniu zabija przepustowość pięćdziesięciokrotnie lub bardziej.

Najczęściej zadawane pytania

Czym jest walidacja JSON Schema w prostych słowach?

Walidacja JSON Schema sprawdza, czy dokument JSON spełnia kontrakt. Kontrakt (schemat) sam jest JSON-em i deklaruje typy, pola wymagane i ograniczenia. Walidator czyta schemat oraz dane i raportuje „przechodzi” albo ścieżki, w których nie przeszło i dlaczego.

Jak walidować JSON względem schematu online?

Wklej schemat i dane do playgroundu na ajv.js.org albo jsonschemavalidator.net i dostaniesz natychmiastowy werdykt. Jeśli JSON wygląda na uszkodzony, najpierw wyczyść go w Formatowaniu JSON online; oba narzędzia działają w przeglądarce i bez wgrywania danych.

Który walidator JSON Schema jest najszybszy w 2026?

W Node Ajv ze skompilowanymi walidatorami załatwia jedno sprawdzenie poniżej mikrosekundy. W Pythonie fastjsonschema generuje kod i dochodzi do klasy Ajv. Na poziomie bramy jsonschema-rs (Rust) i gojsonschema (Go) są 2–5× szybsze od Ajv. Cokolwiek wybierzesz, prekompiluj raz i używaj ponownie.

Jaka jest różnica między JSON Schema a typami TypeScript?

TypeScript sprawdza pisany kod w czasie kompilacji. JSON Schema sprawdza nieznany JSON w czasie wykonania. TypeScript nie widzi JSON-a przychodzącego z odpowiedzi HTTP, z pliku ani od użytkownika; od tego dokładnie jest JSON Schema.

Wybrać Draft 2020-12 czy Draft 7?

Dla nowych projektów w 2026 wybiera się Draft 2020-12. prefixItems, unevaluatedProperties i $dynamicRef rozwiązują realne problemy. OpenAPI 3.1 natywnie używa 2020-12. Przy Draft 7 zostaje się tylko dla kompatybilności z Postmanem albo starszymi usługami. OpenAPI 3.0 używa podzbioru Draft 4; nie miksuj dialektów.

Jak wygenerować JSON Schema z istniejącego JSON?

Opcje są trzy: wkleić próbki na quicktype.io lub jsonschema.net; uruchomić npx genson-js albo pip install genson && genson sample.json w wierszu poleceń; albo napisać ręcznie. Automatycznie wygenerowane schematy bywają zbyt liberalne (każde pole opcjonalne, additionalProperties: true), więc dociśnij je zawsze, zanim potraktujesz jako kontrakty.

Czy JSON Schema może zastąpić OpenAPI?

Nie. OpenAPI używa JSON Schema wewnątrz do opisu ciał żądań i odpowiedzi, a oprócz tego dodaje ścieżki, schematy zabezpieczeń, parametry i adresy serwerów. Komponują się ze sobą: napisz schematy, odwołaj się do nich z dokumentu OpenAPI i masz pełne kontrakty API.

Czy JSON Schema to to samo co JSONPath albo jq?

To różne problemy. JSON Schema waliduje strukturę („czy ten JSON pasuje do kontraktu?”). JSONPath i jq wyciągają wartości („każda nazwa poda w fazie Running”). Walidacja przez schemat; zapytanie przez JSONPath albo jq.

Dlaczego walidacja Ajv przechodzi, ale produkcja odrzuca dane?

Niemal każdy przypadek pokrywa trzech winowajców: brak ajv-formats, więc format: "email" nigdy nie walidował; pominięcie additionalProperties: false, więc dodatkowe pola klienta się prześlizgnęły; użycie additionalProperties: false wewnątrz allOf albo oneOf i odkrycie, że to się nie komponuje. Przełącz na unevaluatedProperties: false.

Czy mogę dostosować komunikaty błędów JSON Schema dla użytkowników końcowych?

Tak. W Node zainstaluj ajv-errors, żeby osadzać errorMessage w schemacie, oraz ajv-i18n dla tłumaczeń w ponad trzydziestu językach. W Pythonie jsonschema udostępnia pełen kontekst walidacji w każdym obiekcie błędu, więc da się mapować typ błędu i ścieżkę na dowolny tekst, którego używa system designu aplikacji.

Powiązane artykuły

Zobacz wszystkie artykuły