ToolHub
View All Posts

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

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 URIStatusGłówne funkcje
Draft 2020-12https://json-schema.org/draft/2020-12/schemaAktualna wersjaprefixItems, dynamicRef, obsługa słownictwa
Draft 2019-09https://json-schema.org/draft/2019-09/schemaWersja stabilnaunevaluatedProperties, $recursiveRef
Draft 7http://json-schema.org/draft-07/schema#Szerokie wsparcieif/then/else, contentEncoding
Draft 6http://json-schema.org/draft-06/schema#Starsza wersjapropertyNames, contains
Draft 4http://json-schema.org/draft-04/schema#PrzestarzałePierwsza szeroko przyjęta wersja
Zalecenie: dla nowych projektów używaj Draft 2020-12. To najnowsza stabilna wersja z największą liczbą funkcji, obsługiwana przez główne biblioteki walidacyjne. Jeśli potrzebujesz maksymalnej kompatybilności z istniejącymi narzędziami, Draft 7 jest bezpiecznym wyborem. Unikaj Draft 4 i wcześniejszych.

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 kluczoweOpisPrzykład
typeOczekiwany typ danych"type": "string" lub "type": ["string", "null"]
enumLista dozwolonych wartości"enum": ["active", "inactive", "pending"]
constMusi być równe tej dokładnej wartości"const": "v2"

Ograniczenia liczbowe

Słowo kluczoweOpisPrzykład
minimumWartość minimalna (włącznie)"minimum": 0
exclusiveMinimumWartość minimalna (wyłącznie)"exclusiveMinimum": 0
maximumWartość maksymalna (włącznie)"maximum": 100
exclusiveMaximumWartość maksymalna (wyłącznie)"exclusiveMaximum": 100
multipleOfMusi być wielokrotnością tej wartości"multipleOf": 0.01

Ograniczenia ciągów znaków

Słowo kluczoweOpisPrzykład
minLengthMinimalna długość ciągu"minLength": 1
maxLengthMaksymalna długość ciągu"maxLength": 255
patternWyrażenie regularne, któremu musi odpowiadać ciąg"pattern": "^[A-Z]{2}\\d{4}$"
formatFormaty semantyczne (email, uri, date-time itp.)"format": "email"

Ograniczenia obiektów

Słowo kluczoweOpisPrzykład
propertiesSchemat dla każdej znanej właściwości"properties": {"name": {"type": "string"}}
requiredLista wymaganych właściwości"required": ["name", "email"]
additionalPropertiesCzy dozwolone są dodatkowe właściwości"additionalProperties": false
minPropertiesMinimalna liczba właściwości"minProperties": 1
maxPropertiesMaksymalna liczba właściwości"maxProperties": 10
patternPropertiesSchemat właściwości pasujących do wyrażenia regularnego"patternProperties": {"^S_": {"type": "string"}}

Ograniczenia tablic

Słowo kluczoweOpisPrzykład
itemsSchemat dla wszystkich elementów tablicy"items": {"type": "string"}
prefixItemsSchemat dla elementów pozycyjnych (Draft 2020-12)"prefixItems": [{"type": "string"}, {"type": "number"}]
minItemsMinimalna liczba elementów"minItems": 1
maxItemsMaksymalna liczba elementów"maxItems": 100
uniqueItemsWszystkie 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:

{
    "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ą:

FormatOpisPrzykład
emailAdres e-mailuser@example.com
uriPrawidłowy URIhttps://example.com/path
uri-referenceURI lub odwołanie względne/path/to/resource
date-timeData i czas ISO 86012026-05-19T14:30:00Z
dateData ISO 86012026-05-19
timeCzas ISO 860114:30:00Z
ipv4Adres IPv4192.168.1.1
ipv6Adres IPv6::1
uuidUniwersalny unikalny identyfikator550e8400-e29b-41d4-a716-446655440000
hostnameNazwa hosta internetowegowww.example.com
Ważna uwaga: domyślnie słowo kluczowe format jest adnotacją, a nie ograniczeniem. Walidatory mogą je ignorować, chyba że jawnie włączysz walidację formatu. W Ajv przekaż { strict: true } lub { validateFormats: true }, aby wymusić sprawdzanie formatu. Zawsze sprawdzaj, czy twój walidator wymusza ograniczenia formatu.

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

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 JSON

FAQ

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.