Przewodnik walidacji JSON Schema: Waliduj swoje struktury danych
Każda aplikacja, która otrzymuje dane z zewnętrznych źródeł, stoi przed tym samym podstawowym pytaniem: czy mogę ufać tym danym? Niezależnie od tego, czy chodzi o treść żądania API, pliki konfiguracyjne, wiadomości z kolejki czy import danych, niezaufane dane muszą zostać zweryfikowane przed wejściem do systemu. JSON Schema zapewnia ustandaryzowany, niezależny od języka sposób definiowania, jak wyglądają prawidłowe dane, i weryfikowania, czy przychodzące dane spełniają tę definicję. Ten przewodnik obejmuje wszystko, od pisania pierwszego schematu po zaawansowane wzorce złożonej walidacji, z praktycznymi przykładami, które możesz natychmiast zastosować.
Czym jest JSON Schema?
JSON Schema to dokument JSON opisujący strukturę i ograniczenia innych dokumentów JSON. Jest to słownictwo umożliwiające adnotację i walidację danych JSON, standaryzowane przez Internet Engineering Task Force (IETF). JSON Schema definiuje reguły dotyczące tego, jakie pola muszą istnieć, jakiego typu muszą być, jakie wartości są dopuszczalne oraz jak powinny być strukturyzowane obiekty i tablice.
Pomyśl o JSON Schema jak o kontrakcie danych. Podobnie jak schemat bazy danych definiuje kolumny, typy i ograniczenia tabeli, JSON Schema definiuje właściwości, typy i ograniczenia dokumentu JSON. Wszelkie dane JSON, które spełniają wszystkie ograniczenia w schemacie, są nazywane prawidłową instancją, podczas gdy dane, które naruszają jakiekolwiek ograniczenie, są nieprawidłowe.
Czym JSON Schema nie jest
- To nie format danych: JSON Schema nie definiuje, jak dane są serializowane lub przesyłane. Opisuje tylko, jak wyglądają prawidłowe dane.
- To nie zamiennik logiki biznesowej: walidacja schematu sprawdza poprawność strukturalną (typy, formaty, zakresy). Złożone reguły biznesowe (takie jak „użytkownik nie może przelać więcej niż jego saldo”) należą do kodu aplikacji.
- To nie schemat bazy danych: chociaż koncepcyjnie podobny, JSON Schema waliduje dokumenty JSON, a nie tabele bazy danych. Możesz jednak używać JSON Schema razem z ograniczeniami bazy danych dla obrony w głąb.
Wersje JSON Schema
JSON Schema przeszedł ewolucję przez wiele wersji roboczych, z których każda dodawała funkcje i udoskonalała słownictwo. Zrozumienie tych wersji pomaga wybrać odpowiednią wersję dla projektu i uniknąć problemów ze zgodnością.
| Wersja | $schema URI | Status | Główne funkcje |
|---|---|---|---|
| Draft 2020-12 | https://json-schema.org/draft/2020-12/schema | Aktualna wersja | prefixItems, dynamicRef, obsługa słownictwa |
| Draft 2019-09 | https://json-schema.org/draft/2019-09/schema | Wersja stabilna | unevaluatedProperties, $recursiveRef |
| Draft 7 | http://json-schema.org/draft-07/schema# | Szerokie wsparcie | if/then/else, contentEncoding |
| Draft 6 | http://json-schema.org/draft-06/schema# | Starsza wersja | propertyNames, contains |
| Draft 4 | http://json-schema.org/draft-04/schema# | Przestarzałe | Pierwsza szeroko przyjęta wersja |
Pisanie pierwszego schematu
Zacznijmy od prostego przykładu: schemat obiektu użytkownika z imieniem, adresem e-mail i wiekiem.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/schemas/user.json",
"title": "User",
"description": "A user account in the system",
"type": "object",
"properties": {
"name": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"description": "The user's full name"
},
"email": {
"type": "string",
"format": "email",
"description": "The user's email address"
},
"age": {
"type": "integer",
"minimum": 0,
"maximum": 150,
"description": "The user's age in years"
}
},
"required": ["name", "email"],
"additionalProperties": false
}Ten schemat deklaruje, że prawidłowy użytkownik musi być obiektem, w którym name i email są wymaganymi właściwościami ciągu znaków. Właściwość age jest opcjonalna, ale jeśli występuje, musi być liczbą całkowitą między 0 a 150. Ograniczenie additionalProperties: false zapobiega wszelkim właściwościom niezdefiniowanym w schemacie, co może wyłapać literówki i nieoczekiwane pola.
Referencja kluczowych słów kluczowych
JSON Schema oferuje bogate słownictwo słów kluczowych do definiowania ograniczeń. Oto najważniejsze słowa kluczowe uporządkowane według kategorii.
Słowo kluczowe type
| Słowo kluczowe | Opis | Przykład |
|---|---|---|
| type | Oczekiwany typ danych | "type": "string" lub "type": ["string", "null"] |
| enum | Lista dozwolonych wartości | "enum": ["active", "inactive", "pending"] |
| const | Musi być równe tej dokładnej wartości | "const": "v2" |
Ograniczenia liczbowe
| Słowo kluczowe | Opis | Przykład |
|---|---|---|
| minimum | Wartość minimalna (włącznie) | "minimum": 0 |
| exclusiveMinimum | Wartość minimalna (wyłącznie) | "exclusiveMinimum": 0 |
| maximum | Wartość maksymalna (włącznie) | "maximum": 100 |
| exclusiveMaximum | Wartość maksymalna (wyłącznie) | "exclusiveMaximum": 100 |
| multipleOf | Musi być wielokrotnością tej wartości | "multipleOf": 0.01 |
Ograniczenia ciągów znaków
| Słowo kluczowe | Opis | Przykład |
|---|---|---|
| minLength | Minimalna długość ciągu | "minLength": 1 |
| maxLength | Maksymalna długość ciągu | "maxLength": 255 |
| pattern | Wyrażenie regularne, któremu musi odpowiadać ciąg | "pattern": "^[A-Z]{2}\\d{4}$" |
| format | Formaty semantyczne (email, uri, date-time itp.) | "format": "email" |
Ograniczenia obiektów
| Słowo kluczowe | Opis | Przykład |
|---|---|---|
| properties | Schemat dla każdej znanej właściwości | "properties": {"name": {"type": "string"}} |
| required | Lista wymaganych właściwości | "required": ["name", "email"] |
| additionalProperties | Czy dozwolone są dodatkowe właściwości | "additionalProperties": false |
| minProperties | Minimalna liczba właściwości | "minProperties": 1 |
| maxProperties | Maksymalna liczba właściwości | "maxProperties": 10 |
| patternProperties | Schemat właściwości pasujących do wyrażenia regularnego | "patternProperties": {"^S_": {"type": "string"}} |
Ograniczenia tablic
| Słowo kluczowe | Opis | Przykład |
|---|---|---|
| items | Schemat dla wszystkich elementów tablicy | "items": {"type": "string"} |
| prefixItems | Schemat dla elementów pozycyjnych (Draft 2020-12) | "prefixItems": [{"type": "string"}, {"type": "number"}] |
| minItems | Minimalna liczba elementów | "minItems": 1 |
| maxItems | Maksymalna liczba elementów | "maxItems": 100 |
| uniqueItems | Wszystkie elementy muszą być unikalne | "uniqueItems": true |
Typowe wzorce schematów
Schematy w rzeczywistym świecie często wymagają wzorców wykraczających poza proste sprawdzanie typów. Oto najczęściej używane wzorce.
Walidacja warunkowa z if/then/else
Używaj logiki warunkowej do stosowania różnych ograniczeń na podstawie wartości właściwości. Na przykład obiekt płatności wymaga różnych pól w zależności od metody płatności.
{
"type": "object",
"properties": {
"method": { "enum": ["credit_card", "bank_transfer"] },
"card_number": { "type": "string" },
"routing_number": { "type": "string" }
},
"required": ["method"],
"if": {
"properties": { "method": { "const": "credit_card" } }
},
"then": {
"required": ["card_number"]
},
"else": {
"required": ["routing_number"]
}
}Kompozycja z allOf, anyOf, oneOf
Słowa kluczowe kompozycji pozwalają łączyć schematy w potężny sposób:
- allOf: Dane muszą spełniać wszystkie pod-Schema. Używane do łączenia wielu ograniczeń lub mieszania fragmentów Schema wielokrotnego użytku.
- anyOf: Dane muszą spełniać co najmniej jeden pod-Schema. Używane dla typów uni, gdzie akceptowalnych jest wiele kształtów.
- oneOf: Dane muszą spełniać dokładnie jeden pod-Schema. Używane dla wzajemnie wykluczających się alternatyw.
{
"oneOf": [
{
"type": "object",
"properties": {
"type": { "const": "email" },
"address": { "type": "string", "format": "email" }
},
"required": ["type", "address"]
},
{
"type": "object",
"properties": {
"type": { "const": "phone" },
"number": { "type": "string", "pattern": "^\\+?[1-9]\\d{1,14}$" }
},
"required": ["type", "number"]
}
]
}Ponowne użycie schematu z $ref
Słowo kluczowe $ref pozwala odwoływać się do Schema i ponownie go używać, eliminując powtórzenia i utrzymując łatwość utrzymania Schema. Możesz odwoływać się do Schema w tym samym dokumencie lub w plikach zewnętrznych.
{
"$id": "https://example.com/schemas/order.json",
"type": "object",
"properties": {
"customer": { "$ref": "#/$defs/address" },
"shipping": { "$ref": "#/$defs/address" },
"billing": { "$ref": "#/$defs/address" },
"items": {
"type": "array",
"items": { "$ref": "#/$defs/lineItem" },
"minItems": 1
}
},
"required": ["customer", "items"],
"$defs": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"zip": { "type": "string", "pattern": "^\\d{5}(-\\d{4})?$" },
"country": { "type": "string", "minLength": 2, "maxLength": 2 }
},
"required": ["street", "city", "zip", "country"]
},
"lineItem": {
"type": "object",
"properties": {
"product": { "type": "string" },
"quantity": { "type": "integer", "minimum": 1 },
"price": { "type": "number", "exclusiveMinimum": 0 }
},
"required": ["product", "quantity", "price"]
}
}
}Typ nullable
W JSON Schema Draft 2020-12 typy nullable są reprezentowane przez tablicę typów zawierającą "null":
{
"type": ["string", "null"],
"description": "An optional display name, or null if not set"
}We wcześniejszych wersjach roboczych specyfikacja OpenAPI używała słowa kluczowego nullable: true. W przypadku standardowego JSON Schema zawsze używaj podejścia z tablicą typów.
Walidacja formatu
Słowo kluczowe format zapewnia walidację semantyczną wykraczającą poza kontrolę struktury. Określa, że string musi być zgodny z dobrze znanym formatem. Powszechnie obsługiwane formaty obejmują:
| Format | Opis | Przykład |
|---|---|---|
| Adres e-mail | user@example.com | |
| uri | Prawidłowy URI | https://example.com/path |
| uri-reference | URI lub odwołanie względne | /path/to/resource |
| date-time | Data i czas ISO 8601 | 2026-05-19T14:30:00Z |
| date | Data ISO 8601 | 2026-05-19 |
| time | Czas ISO 8601 | 14:30:00Z |
| ipv4 | Adres IPv4 | 192.168.1.1 |
| ipv6 | Adres IPv6 | ::1 |
| uuid | Uniwersalny unikalny identyfikator | 550e8400-e29b-41d4-a716-446655440000 |
| hostname | Nazwa hosta internetowego | www.example.com |
Programowa walidacja danych JSON
Walidacja Schema jest najbardziej przydatna, gdy jest zintegrowana z kodem aplikacji. Oto przykłady z użyciem popularnych bibliotek w różnych językach.
JavaScript z Ajv
Ajv jest najczęściej używanym walidatorem JSON Schema w JavaScripcie. Obsługuje wszystkie wersje robocze i oferuje doskonałą wydajność dzięki kompilacji JIT Schema.
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
const ajv = new Ajv();
addFormats(ajv);
const schema = {
type: 'object',
properties: {
name: { type: 'string', minLength: 1 },
email: { type: 'string', format: 'email' },
age: { type: 'integer', minimum: 0 }
},
required: ['name', 'email'],
additionalProperties: false
};
const validate = ajv.compile(schema);
const valid = validate({ name: 'Alice', email: 'alice@example.com', age: 30 });
if (!valid) {
console.log(validate.errors);
// [{ keyword: 'required', params: { missingProperty: 'email' }, ... }]
}Python z jsonschema
from jsonschema import validate, ValidationError
schema = {
"type": "object",
"properties": {
"name": {"type": "string", "minLength": 1},
"email": {"type": "string", "format": "email"},
"age": {"type": "integer", "minimum": 0}
},
"required": ["name", "email"],
"additionalProperties": False
}
try:
validate(instance={"name": "Alice", "email": "alice@example.com"}, schema=schema)
except ValidationError as e:
print(f"Validation failed: {e.message}")Walidacja danych API za pomocą JSON Schema
Jednym z najcenniejszych zastosowań JSON Schema jest walidacja danych żądań i odpowiedzi API. Zapewnia to, że twoje API otrzymuje dobrze sformatowane dane wejściowe i zwraca dane w oczekiwanym formacie, umożliwiając wczesne wykrywanie błędów i dostarczanie klientom jasnych komunikatów o błędach.
Middleware Express.js
import Ajv from 'ajv';
const ajv = new Ajv({ allErrors: true });
function validateBody(schema) {
const validate = ajv.compile(schema);
return (req, res, next) => {
if (!validate(req.body)) {
return res.status(400).json({
error: 'Validation failed',
details: validate.errors
});
}
next();
};
}
app.post('/api/users',
validateBody({
type: 'object',
properties: {
name: { type: 'string', minLength: 1, maxLength: 100 },
email: { type: 'string', format: 'email' },
role: { enum: ['admin', 'editor', 'viewer'] }
},
required: ['name', 'email'],
additionalProperties: false
}),
(req, res) => {
// req.body is guaranteed valid here
createUser(req.body);
}
);OpenAPI a JSON Schema
OpenAPI (dawniej Swagger) używa podzbioru JSON Schema do definiowania Schema żądań i odpowiedzi API. Jeśli już używasz OpenAPI, możesz wyodrębnić Schema ze specyfikacji API i użyć ich do walidacji w czasie wykonywania. Narzędzia takie jak openapi-schema-validator i express-openapi-validator mogą zautomatyzować ten proces, zapewniając, że dokumentacja API i logika walidacji pozostają zawsze zsynchronizowane.
Najlepsze praktyki
- Zawsze ustawiaj $schema: dołącz słowo kluczowe $schema, aby zadeklarować wersję roboczą używaną przez Twój schemat. Zapobiega to niejednoznaczności i zapewnia, że walidator prawidłowo interpretuje Twój schemat.
- Używaj $id jako identyfikatora schematu: słowo kluczowe $id zapewnia unikalny identyfikator dla Twojego schematu i służy jako bazowy URI do rozwiązywania odwołań $ref. Zawsze go ustawiaj, nawet dla lokalnych schematów.
- Ustawiaj additionalProperties: false: domyślnie JSON Schema zezwala na wszelkie dodatkowe właściwości w obiektach. Ustawienie additionalProperties: false wyłapuje literówki i nieoczekiwane pola, czyniąc Twój schemat bardziej rygorystycznym, a API bardziej przewidywalnym.
- Używaj $defs do przechowywania komponentów wielokrotnego użytku: definiuj wspólne schematy w $defs i odwołuj się do nich za pomocą $ref. Zmniejsza to powielanie i ułatwia utrzymanie schematów.
- Dodawaj opisy: każda właściwość i schemat powinny mieć pole description. Służy to zarówno jako dokumentacja, jak i pomaga innym deweloperom zrozumieć przeznaczenie i ograniczenia każdego pola.
- Waliduj na granicach systemu: stosuj walidację schematu na krawędziach systemu: punktach końcowych API, konsumentach wiadomości, potokach importu danych i loaderach konfiguracji. Nie waliduj danych, które Twój własny kod już wyprodukował i którym ufa.
- Włącz tryb ścisły w walidatorze: skonfiguruj walidator, aby odrzucał nieznane słowa kluczowe, wymuszał walidację formatu i raportował wszystkie błędy zamiast zatrzymywać się na pierwszym. To wyłapuje więcej problemów w jednym przebiegu walidacji.
- Wersjonuj schematy: dołączaj wersję schematu w URI $id (np. https://example.com/schemas/user/v2.json). Pozwala to na ewolucję schematu bez łamania istniejących konsumentów.
- Testuj swój schemat: pisz testy jednostkowe dla swojego schematu z prawidłowymi i nieprawidłowymi przykładami. Zapewnia to, że Twój schemat wymusza zamierzone ograniczenia i wyłapuje regresje przy modyfikacjach schematu.
- Używaj format do walidacji semantycznej: preferuj format: "email" zamiast skomplikowanych wzorców wyrażeń regularnych. Format jest bardziej czytelny, łatwiejszy w utrzymaniu i korzysta z dobrze przetestowanej logiki walidacji w bibliotekach walidatorów.
Potrzebujesz sprawdzić poprawność danych JSON względem schematu? Wypróbuj nasz darmowy walidator JSON Schema online. Wklej swój schemat i dane, aby uzyskać natychmiastowe wyniki walidacji ze szczegółowymi komunikatami błędów.
Walidator JSON SchemaNarzędzia do formatowania JSONFAQ
Czym jest JSON Schema?
JSON Schema to dokument JSON opisujący strukturę i ograniczenia innych dokumentów JSON. Pozwala definiować wymagane pola, oczekiwane typy danych, zakresy wartości, wzorce stringów i struktury zagnieżdżonych obiektów. Możesz go używać do walidacji danych wejściowych, generowania dokumentacji i automatycznego tworzenia interfejsów formularzy.
Której wersji JSON Schema powinienem używać?
W przypadku nowych projektów używaj JSON Schema Draft 2020-12. To najnowsza stabilna wersja, obsługiwana przez główne biblioteki walidacyjne, takie jak Ajv. Jeśli potrzebujesz kompatybilności ze starszymi narzędziami, Draft 7 jest również szeroko obsługiwany. Unikaj Draft 4 i wcześniejszych, ponieważ używają przestarzałych słów kluczowych i nie mają nowoczesnych funkcji.
Jaka jest różnica między JSON Schema a interfejsem TypeScript?
Interfejsy TypeScript zapewniają tylko sprawdzanie typów w czasie kompilacji w kodzie TypeScript. JSON Schema zapewnia walidację w czasie wykonywania w różnych językach programowania, mogąc walidować dane z dowolnego źródła (żądania API, pliki, bazy danych). Użyj TypeScript dla bezpieczeństwa w czasie rozwoju, a JSON Schema do walidacji danych w czasie wykonywania na granicach systemu.
Czy JSON Schema może walidować treść żądania API?
Tak, JSON Schema jest szeroko stosowany do walidacji żądań i odpowiedzi API. Frameworki takie jak Express (z express-json-validator), FastAPI i Spring Boot obsługują walidację JSON Schema natywnie lub przez middleware. Walidacja treści żądań według schematu zapewnia, że przychodzące dane mają prawidłową strukturę przed przetworzeniem przez aplikację.
Jakie są najważniejsze słowa kluczowe JSON Schema?
Najważniejsze słowa kluczowe to: type (typ danych), properties (pola obiektu), required (wymagane pola), items (schemat elementów tablicy), minimum/maximum (granice liczbowe), minLength/maxLength (granice ciągów), pattern (wyrażenie regularne dla ciągów), enum (dozwolone wartości) i $ref (odwołania do ponownego użycia schematu). Te słowa kluczowe pokrywają zdecydowaną większość potrzeb walidacyjnych.