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ą.
| Wymiar | Sprawdzenie składni JSON | Walidacja JSON Schema |
|---|---|---|
| Co sprawdza | Czy to jest poprawny dokument JSON? | Czy ten JSON pasuje do kontraktu? |
| Wykrywa | Brakujące przecinki, pojedyncze cudzysłowy, komentarze | Niewłaściwe typy, brakujące pola wymagane, wartości spoza zakresu |
| Narzędzia | JSON.parse(), Formatowanie JSON online | Ajv, jsonschema (Python), fastjsonschema |
| Kiedy po nie sięgnąć | Najpierw, przed parsowaniem | Tuż 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ędzie | Pytanie, na które odpowiada | Kiedy po nie sięgnąć |
|---|---|---|
| JSON Schema | Czy ten JSON pasuje do oczekiwanej struktury? | Walidacja wejścia API, plików konfiguracyjnych, payloadów formularzy |
| JSONPath | Jak 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 |
| jq | Jak przetwarzać JSON w wierszu poleceń? | Skrypty powłoki, potoki logów, kontrole CI |
| Typy TypeScript | Czy 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.
| Wymiar | JSON Schema | OpenAPI |
|---|---|---|
| Zakres | Kształt jednego dokumentu JSON | Kształt całego API HTTP |
| Zależności | Brak (schemat to samowystarczalny JSON) | Importuje JSON Schema do definicji ciał |
| Sparowanie wersji | Draft 7 / Draft 2019-09 / Draft 2020-12 | OpenAPI 3.0 używa podzbioru Draft 4; OpenAPI 3.1 używa Draft 2020-12 natywnie |
| Typowe zastosowanie | Pliki konfiguracyjne, koperty wiadomości, walidacja formularzy, kontrakty pojedynczych payloadów | Projektowanie REST API, generowanie SDK, mock serwery, testy kontraktowe |
| Generowanie kodu | Ograniczone (kilka narzędzi w stylu quicktype) | Dojrzały ekosystem (openapi-generator, oapi-codegen, SDK dostawców) |
| Zarządzanie kontraktem | Jeden 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:
type—string,number,integer,boolean,null,array,objectproperties+required— deklaruje pola i oznacza, które muszą wystąpićenum/const— ogranicza do ustalonego zbioru lub jednego literałuminimum/maximum/multipleOf— ograniczenia liczboweminLength/maxLength/pattern— długość ciągu i wyrażenie regularneminItems/maxItems/uniqueItems— kształt tablicyadditionalProperties: falseodrzuca 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.
| Wymiar | jsonschema | Pydantic v2 |
|---|---|---|
| Format schematu | Słownik JSON (schemat to dane) | Klasa Pythona z adnotacjami typów |
| Wydajność | Interpretowany, ~10–100× wolniejszy od Pydantic | Rdzeń w Rust, najszybszy w ekosystemie |
| Przenośność między językami | Tak (ten sam schemat działa w JS, Go, Rust) | Nie (tylko Python) |
| Integracja z FastAPI / natywnymi modelami | Konwersja ręczna | Wbudowana |
Pełne słowa kluczowe Draft 2020-12 ($dynamicRef itp.) | Kompletne | Częś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:
- UX — natychmiastowa informacja zwrotna podczas pisania bije roundtripem do serwera na głowę.
- Pasmo — oczywiste błędy nigdy nie opuszczają przeglądarki.
- 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ń nafastjsonschema, który generuje kod Pythona i ląduje blisko Ajv.- Rust i Go:
jsonschema-rsixeipuuv/gojsonschemadają 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.