JSON-Schema-Validierung: JSON in Node, Python und im Browser prüfen (2026)
TL;DR: Ein JSON Schema ist ein Vertrag für JSON-Daten. Sie deklarieren Feldtypen, Pflichtfelder und Einschränkungen, und ein Validator prüft, ob ein beliebiges JSON-Dokument diesen Vertrag erfüllt. Verwenden Sie Ajv in Node für die schnellste Validierung, die Bibliothek jsonschema in Python für portable Schemas und bündeln Sie Ajv im Browser, um Formularen und Konfigurationen sofortiges Feedback zu geben. Draft 2020-12 ist die Version, die Sie 2026 für neue Projekte wählen sollten.
Was Sie hier finden: das kleinstmögliche funktionierende Beispiel, durchgängige Muster für alle drei Laufzeiten und die Praxisfallen, die zu „Validierung erfolgreich, Produktion lehnt die Daten trotzdem ab”-Bugs führen.
Was JSON Schema ist (und was nicht)
Eine Definition in einem Satz
Ein JSON Schema ist ein JSON-Dokument, das die Struktur anderer JSON-Dokumente beschreibt. Ein Validator liest das Schema und die Daten ein, bestätigt anschließend die Konformität oder gibt die fehlerhaften Pfade zurück.
Das kleinste nützliche Beispiel:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": { "name": { "type": "string" } },
"required": ["name"]
}
{"name": "Alice"} besteht. {"age": 30} schlägt fehl (kein name). {"name": 42} schlägt fehl (name ist keine Zeichenkette). Das ist das gesamte mentale Modell.
JSON Schema vs. JSON-Syntaxprüfung
Zwei verschiedene Probleme, die häufig verwechselt werden.
| Dimension | JSON-Syntaxprüfung | JSON-Schema-Validierung |
|---|---|---|
| Was wird geprüft | Ist das ein gültiges JSON-Dokument? | Erfüllt dieses JSON den Vertrag? |
| Erkennt | Fehlende Kommas, einfache Anführungszeichen, Kommentare | Falsche Typen, fehlende Pflichtfelder, Werte außerhalb des Bereichs |
| Werkzeuge | JSON.parse(), JSON-Formatierer | Ajv, jsonschema (Python), fastjsonschema |
| Wann einsetzen | Als Erstes, vor dem Parsen | Direkt nach dem Parsen, vor der Geschäftslogik |
In der Praxis machen Sie beides: Sie formatieren die Payload im JSON-Formatierer, um zu bestätigen, dass sie überhaupt parst, und schicken sie anschließend durch ein Schema, um die Vertragstreue zu prüfen.
JSON Schema vs. JSONPath, JSON Patch, jq und TypeScript
Fünf Werkzeuge teilen sich diesen Problemraum. Die Entscheidungsmatrix:
| Werkzeug | Welche Frage es beantwortet | Wann es passt |
|---|---|---|
| JSON Schema | Erfüllt dieses JSON die erwartete Struktur? | Validierung von API-Eingaben, Konfigurationsdateien, Formular-Payloads |
| JSONPath | Wie lese ich einen Wert aus diesem JSON aus? | Verschachtelte Felder extrahieren, Massenlesezugriffe |
| JSON Patch (RFC 6902) | Wie beschreibe ich den Diff von A nach B? | Kollaboratives Editieren, inkrementelle Synchronisation |
| jq | Wie verarbeite ich JSON auf der Kommandozeile? | Shell-Skripte, Log-Pipelines, CI-Checks |
| TypeScript-Typen | Verwendet mein Code diese Struktur korrekt? | Compile-Zeit-Garantien innerhalb einer Codebasis |
JSON Schema validiert unbekannte Daten zur Laufzeit, TypeScript prüft bekannten Code zur Übersetzungszeit. TypeScript hilft nicht bei JSON aus einem Drittanbieter-Webhook oder einer Nutzereingabe; genau dafür gibt es JSON Schema. Zod und Pydantic stehen dazwischen (Compile-Zeit-Typen plus Laufzeitvalidierung), dazu unten mehr.
JSON Schema vs. OpenAPI
Ein verbreitetes Missverständnis: OpenAPI ersetze JSON Schema. Tut es nicht. OpenAPI nutzt JSON Schema intern, um Request- und Response-Bodys zu beschreiben, und legt dann Pfade, Parameter, Sicherheitsschemata und Server-URLs darüber. Das Schema ist der Vertrag über die Datenform; OpenAPI ist der API-Vertrag, der dieses Schema umhüllt.
| Dimension | JSON Schema | OpenAPI |
|---|---|---|
| Geltungsbereich | Form eines einzelnen JSON-Dokuments | Form einer kompletten HTTP-API |
| Abhängigkeiten | Keine (Schema ist eigenständiges JSON) | Importiert JSON Schema für Body-Definitionen |
| Versionspaarung | Draft 7 / Draft 2019-09 / Draft 2020-12 | OpenAPI 3.0 nutzt eine Draft-4-Teilmenge; OpenAPI 3.1 nutzt Draft 2020-12 nativ |
| Typischer Einsatz | Konfigurationsdateien, Nachrichtenhüllen, Formularvalidierung, Einzel-Payload-Verträge | REST-API-Design, SDK-Generierung, Mock-Server, Vertragstests |
| Codegenerierung | Begrenzt (einige quicktype-ähnliche Werkzeuge) | Reifes Ökosystem (openapi-generator, oapi-codegen, Hersteller-SDKs) |
| Vertragsmanagement | Eine Datei pro Form, kein Routing | Pfade, Operationen, Auth-Flows, versionierte Endpunkte in einem Dokument |
Greifen Sie zu reinem JSON Schema, wenn das Artefakt, um das es geht, ein einzelnes Dokument ist: ein Webhook-Payload, eine Konfigurationsdatei, eine Queue-Nachricht oder ein Formular. Es gibt keine HTTP-Oberfläche zu beschreiben, daher wäre OpenAPI Mehraufwand.
Greifen Sie zu OpenAPI, wenn Sie eine HTTP-API veröffentlichen und ein Dokument haben wollen, das Doku, SDK-Generierung, Mock-Server und Vertragstests speist. Definieren Sie Ihre Schemas zuerst als eigenständige JSON-Schema-Dateien in einem schemas/-Verzeichnis und referenzieren Sie sie dann per $ref aus dem OpenAPI-Dokument. So bleiben die Schemas außerhalb des API-Kontexts wiederverwendbar.
Die Versionspaarung bringt Teams ins Stolpern. OpenAPI 3.0 nutzt eine Draft-4-Teilmenge, Sie können also keine Draft-2020-12-Schlüsselwörter wie prefixItems oder unevaluatedProperties in einem 3.0-Dokument verwenden — die Generatoren ignorieren sie stillschweigend. OpenAPI 3.1 ist eine Obermenge von Draft 2020-12, alles in 2020-12 Gültige ist also auch in 3.1 gültig. Wenn Sie die Wahl haben, zielen Sie auf OpenAPI 3.1 und schreiben Sie überall Draft-2020-12-Schemas.
Ihr erstes JSON Schema (5 Minuten)
Die Schlüsselwörter, die Sie zuerst brauchen
Mit diesen kommen Sie 80 % des Wegs:
{
"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
}
Das Vokabular:
type:string,number,integer,boolean,null,array,objectproperties+required: Felder deklarieren und kennzeichnen, welche vorhanden sein müssenenum/const: auf eine feste Menge oder einen einzelnen Literalwert beschränkenminimum/maximum/multipleOf: numerische GrenzenminLength/maxLength/pattern: Zeichenkettenlänge und RegexminItems/maxItems/uniqueItems: Array-FormadditionalProperties: false: nicht deklarierte Schlüssel ablehnen (für Eingabeverträge immer setzen)
JSON-Schema-Beispiele nach Anwendungsfall
Die obigen Schlüsselwörter tauchen je nach Validierungsziel in unterschiedlichen Kombinationen auf. Ein paar typische Formen:
API-Request-Body — ein Signup-Endpunkt, der E-Mail und Passwort akzeptiert:
{
"type": "object",
"properties": {
"email": { "type": "string", "format": "email" },
"password": { "type": "string", "minLength": 8, "maxLength": 128 }
},
"required": ["email", "password"],
"additionalProperties": false
}
Konfigurationsdatei — eine Logger-Konfiguration, die das Level auf eine feste Menge festnagelt:
{
"type": "object",
"properties": {
"level": { "enum": ["debug", "info", "warn", "error"] },
"output": { "type": "string", "default": "stdout" }
},
"required": ["level"],
"additionalProperties": false
}
Formular-Payload mit bedingten Regeln — wenn accountType den Wert "business" hat, wird taxId zur Pflicht:
{
"type": "object",
"properties": {
"accountType": { "enum": ["personal", "business"] },
"taxId": { "type": "string" }
},
"if": { "properties": { "accountType": { "const": "business" } } },
"then": { "required": ["taxId"] }
}
CSV-Zeile als JSON-Datensatz — eine Zeile aus einer exportierten Bestelltabelle:
{
"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"]
}
Webhook-Event-Hülle — oneOf unterscheidet anhand des type-Literals, jede Event-Variante hat also ihre eigene Payload-Form:
{
"oneOf": [
{ "properties": { "type": { "const": "order.created" }, "data": { "$ref": "#/$defs/order" } } },
{ "properties": { "type": { "const": "order.refunded" }, "data": { "$ref": "#/$defs/refund" } } }
]
}
Diese fünf Beispiele decken den Großteil dessen ab, was Teams in der Praxis schreiben. Kopieren Sie die nächstgelegene Form und passen Sie Feldnamen an — das Schlüsselwort-Vokabular bleibt gleich.
Validieren ohne Installation
Fügen Sie Schema und Payload in den Playground unter ajv.js.org oder jsonschemavalidator.net ein und Sie erhalten sofort ein Urteil. Wenn das JSON selbst verdächtig aussieht, schicken Sie es zuerst durch den JSON-Formatierer.
Validieren in Node.js mit Ajv
Installation und ein 12-Zeilen-Beispiel
Ajv kompiliert Ihr Schema beim ersten compile-Aufruf zu einer optimierten Funktion und verwendet diese danach wieder.
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");
Auf Draft 2020-12 umschalten
Der Standardkonstruktor Ajv ist aus Gründen der Abwärtskompatibilität immer noch auf Draft 7 festgelegt. Schalten Sie 2020-12 explizit ein:
import Ajv2020 from "ajv/dist/2020";
const ajv = new Ajv2020({ strict: true, allErrors: true });
Jetzt stehen prefixItems, unevaluatedProperties und $dynamicRef zur Verfügung. Was jedes davon leistet, finden Sie weiter unten im Abschnitt zu Draft 2020-12.
format-Validierung aktivieren
Diese Falle erwischt mehr Entwickler als jede andere Eigenheit von Ajv: format: "email" tut standardmäßig nichts. Die Spezifikation behandelt format als unverbindlichen Hinweis, daher müssen Sie das Format-Modul registrieren:
npm install ajv-formats
import addFormats from "ajv-formats";
addFormats(ajv); // jetzt validiert "format": "email" tatsächlich
Ohne diesen Schritt besteht {"email": "not-an-email"} ein Schema, das format: "email" verlangt. Installieren Sie ajv-formats in der Produktion immer.
Express-Middleware im Ernstfall
Ein Validator pro Route, beim Start kompiliert:
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 });
}
// ... Geschäftslogik
res.status(201).json({ ok: true });
});
Der teuerste Fehler dabei: ajv.compile(schema) innerhalb des Request-Handlers aufrufen. Kompilieren Sie einmal auf Modulebene und verwenden Sie die zurückgegebene Funktion wieder. Erneutes Kompilieren pro Anfrage drückt den Durchsatz um Faktor 50 oder mehr.
Validieren in Python mit jsonschema
Installation und Grundnutzung
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))
Alle Fehler mit Draft202012Validator einsammeln
validate() wirft beim ersten Fehler. Um alle Probleme auf einmal aufzulisten (nützlich für Formularantworten), nutzen Sie 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}")
So kann der Nutzer alles auf einmal beheben, statt mehrere Runden zu drehen.
jsonschema vs. Pydantic: Wann welche Wahl
Zwei starke Python-Bibliotheken, zwei verschiedene Aufgaben.
| Dimension | jsonschema | Pydantic v2 |
|---|---|---|
| Schemaformat | Ein JSON-Dict (das Schema ist Daten) | Eine Python-Klasse mit Type Hints |
| Performance | Interpretiert, ~10–100× langsamer als Pydantic | Rust-Kern, das Schnellste im Ökosystem |
| Sprachübergreifende Portabilität | Ja (dasselbe Schema läuft in JS, Go, Rust) | Nein (nur Python) |
| Native FastAPI-/Modell-Integration | Manuelle Konvertierung | Eingebaut |
Vollständige Draft-2020-12-Schlüsselwörter ($dynamicRef etc.) | Vollständig | Teilweise |
Eine brauchbare Faustregel: jsonschema für sprachübergreifende Verträge (OpenAPI, öffentliche APIs, Webhooks), Pydantic für interne Python-Dienste. Viele Teams setzen beides ein, jsonschema am Gateway zur Vertragsdurchsetzung und Pydantic auf Anwendungsebene für typisierte Geschäftslogik. Das Schema ist das portable Artefakt, identisch zu dem, was Sie an Ajv übergeben würden.
Validieren im Browser
Warum überhaupt clientseitig validieren
Drei Gründe, vom wichtigsten zum am wenigsten wichtigen:
- UX: Sofortiges Feedback während der Eingabe schlägt jeden Server-Round-Trip.
- Bandbreite: Offensichtliche Fehler verlassen den Browser gar nicht erst.
- Security-Hygiene: Reduziert Müllvolumen am Backend, ersetzt aber keine Server-Validierung.
Vertrauen Sie niemals nur der clientseitigen Validierung. Validieren Sie auf dem Server erneut.
Ajv für den Browser bündeln
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"]
});
Das Bundle wächst um etwa 30 KB gzipped: spürbar, aber nicht katastrophal. Teams setzen Ajv ein, wenn sie eine Schemadefinition zwischen Server und Client teilen wollen.
Leichtere Alternativen: Zod und Valibot
Wenn Sie das JSON-Schema-Ökosystem nicht brauchen und ohnehin in TypeScript arbeiten, liefert Ihnen ein TS-nativer Validator kleinere Bundles und engere Typinferenz:
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 kommt mit etwa 3 KB gzipped und einer ähnlichen API. Wählen Sie es, wenn die Bundle-Größe entscheidend ist. Der Haken: Keine der beiden Bibliotheken erzeugt JSON Schema. Wenn Sie eine einzige Quelle der Wahrheit brauchen, die Sie mit Backends, Drittanbieter-Clients oder OpenAPI-Generatoren teilen, bleiben Sie bei Ajv. Ist alles Ihr eigenes TypeScript, sind Zod und Valibot ergonomischer.
Was Draft 2020-12 hinzufügt
prefixItems für Tupel-Validierung
Draft 7 drückte Tupel über items: [] plus additionalItems aus. Draft 2020-12 trennt das sauber:
{
"type": "array",
"prefixItems": [
{ "type": "string" },
{ "type": "number" }
],
"items": false
}
["x", 42] besteht. ["x", 42, "extra"] schlägt fehl. Das Schema liest sich genau so, wie es sich verhält.
unevaluatedProperties für zusammengesetzte Schemas
Ein subtiler Bug, der jedes Team trifft, das allOf oder oneOf einsetzt: additionalProperties: false prüft nur die unmittelbare Ebene, auf der es steht. Geschwister-Subschemas innerhalb von allOf deklarieren, was sie wollen. Die Lösung in 2020-12 heißt unevaluatedProperties: false:
{
"allOf": [
{ "$ref": "#/$defs/base" }
],
"unevaluatedProperties": false
}
Damit werden alle Properties verworfen, die von keinem Zweig ausgewertet wurden, also genau das Verhalten, das die meisten Entwickler von additionalProperties: false erwarten.
$dynamicRef für rekursive Schemas
Wer schon einmal versucht hat, ein rekursives Baum-Schema in Draft 7 zu deklarieren, kennt die nötigen Verrenkungen. $dynamicRef plus $dynamicAnchor räumt damit auf:
{
"$dynamicAnchor": "node",
"type": "object",
"properties": {
"value": { "type": "string" },
"children": { "type": "array", "items": { "$dynamicRef": "#node" } }
}
}
Die Rekursion ist deklarativ und lässt sich von Nachfahren überschreiben, ohne $id umschreiben zu müssen.
Draft 7 vs. 2020-12: Welche Version
- Neues Projekt, moderne Toolchain → Draft 2020-12
- Erstellung oder Konsum von OpenAPI 3.1 → 2020-12 ist der native Dialekt
- Arbeit mit OpenAPI 3.0 oder älteren Diensten → Draft 4 (OpenAPI 3.0 nutzt eine Draft-4-Teilmenge; Dialekte nicht mischen)
- Breite Validator-Kompatibilität nötig (Postman, ältere CI-Werkzeuge) → Draft 7 ist nach wie vor das sicherste Austauschformat
Jeder moderne Validator (Ajv, Python jsonschema, jsonschema-rs, Javas networknt/json-schema-validator) unterstützt 2020-12 heute.
Praxismuster
API-Eingabevalidierung
Die Express-Middleware oben ist die Produktionsform. Zwei Praktiken obendrauf: Halten Sie alle Schemas in einem Verzeichnis schemas/ im Repo-Root und ergänzen Sie einen CI-Schritt, der ajv test (oder das Python-Äquivalent) ausführt, um die Schemas selbst gegen das JSON-Schema-Meta-Schema zu validieren.
Konfigurationsdateien
Visual Studio Code bringt eine Integration mit SchemaStore mit: Autovervollständigung und Inline-Validierung für package.json, tsconfig.json und Dutzende mehr. Fügen Sie Ihren eigenen Konfigurationen ein $schema-Feld hinzu, und Editor-Nutzer bekommen dieselbe Behandlung.
CI-Test-Fixtures
Test-Fixtures veralten. Jemand aktualisiert ein Modell, eine Fixture bleibt auf der alten Form, der Test besteht trotzdem, weil die Assertions das geänderte Feld nie berührt haben. Fangen Sie das mit einer Schema-Prüfung ab, bevor die Assertions laufen:
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)}`);
}
Wenn die Schema-Prüfung anschlägt, ist der nächste Schritt meist ein struktureller Diff. Ziehen Sie die Fixture in JSON vergleichen gegen ein frisches Produktions-Sample, um zu sehen, was abgewichen ist. Wenn Zeitstempel und IDs den Diff dominieren, wenden Sie die Pfad-Ignore-Muster für Snapshots aus dem JSON-Diff-Guide an, um Signal von Rauschen zu trennen.
Webhook-Payloads (Stripe, GitHub)
Drittanbieter-Webhooks gehören zu den wertvollsten Einsatzorten für JSON Schema. Der Webhook ist ein Vertrag; der Anbieter kann ihn ändern; Sie wollen es im selben Moment merken, in dem das passiert. Stripe und GitHub veröffentlichen OpenAPI-Beschreibungen, aus denen sich JSON Schemas extrahieren lassen. Validieren Sie eingehende Events, dann leuchtet ein brechendes Upgrade in Ihrem Monitoring auf, anstatt still den Zustand zu beschädigen.
Schemagetriebene Formularvalidierung
React Hook Form bietet einen Adapter @hookform/resolvers/ajv; Vues VeeValidate hat ein gleichwertiges Ajv-Plugin. Beide steuern Formular-Rendering, Fehlermeldungen und Submit-Validierung aus einem einzigen JSON Schema. Das Schema ist die einzige Quelle der Wahrheit, und die UI erbt seine Regeln.
Freundliche Fehlermeldungen
Warum die Standardausgaben hart sind
Out of the box produziert Ajv Fehler wie #/properties/email format must match "email". Für einen Entwickler, der einen 400er debuggt, in Ordnung. Für einen Nutzer, der ein Checkout-Formular ausfüllt, unbrauchbar.
ajv-errors für eigene Meldungen
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: "Bitte geben Sie eine gültige E-Mail-Adresse ein" },
required: { email: "E-Mail ist erforderlich" }
}
};
Das Schlüsselwort errorMessage bleibt im Schema, sodass Validierungsregeln und nutzerseitige Texte gemeinsam wandern.
ajv-i18n für übersetzte Fehler
ajv-i18n liefert Übersetzungen der Standardmeldungen in über 30 Sprachen mit. Eine Zeile beim Start, und Ihr Validator spricht Spanisch, Französisch, Japanisch oder welches Locale auch immer Sie bedienen. Nützlich als Fallback, wenn Ihre errorMessage-Überschreibungen nicht jede Einschränkung abdecken.
Schema-Pfade auf Formularfelder abbilden
Jeder Ajv-Fehler hat einen instancePath wie /users/0/email. Die meisten Formular-Bibliotheken erwarten Punktpfade wie users[0].email. Einzeiler:
const fieldPath = error.instancePath.replace(/^\//, "").replace(/\//g, ".");
In Pythons jsonschema liegt das Äquivalent unter error.absolute_path. Mit . verbinden, gleiches Ergebnis.
Fünf Fallen, die die Validierung passieren und in der Produktion crashen
1. format ist standardmäßig nur ein Hinweis
Ohne ajv-formats plus addFormats(ajv) ist jedes format-Schlüsselwort wirkungslos. {"format": "email"} akzeptiert "not-an-email". Installieren Sie das Format-Paket in der Produktion immer.
2. additionalProperties steht standardmäßig auf true
Ohne additionalProperties: false akzeptiert Ihr Schema jedes nicht deklarierte Feld. Clients können zusätzliche Felder mitliefern, die die Validierung komplett umgehen. Machen Sie additionalProperties: false zum Standard für Eingabeverträge; lockern Sie es bewusst, wenn nötig.
3. additionalProperties komponiert nicht
Innerhalb von allOf, oneOf oder anyOf inspiziert additionalProperties: false nur die Properties auf seiner eigenen Ebene. Geschwister-Subschemas rutschen durch. Die Draft-2020-12-Lösung heißt unevaluatedProperties: false.
4. Remote-$ref ist ein Produktionsrisiko
$ref: "https://example.com/schema.json" lässt Ajv beim ersten compile über das Netzwerk nachladen. Das bedeutet Latenz, DoS-Exposition, falls der Remote-Host hängt, und eine MITM-Angriffsfläche. Inlinen Sie alle $ref-Ziele oder laden Sie sie zur Build-Zeit von der Festplatte.
5. Generierte Schemas driften gegenüber den echten Daten
Werkzeuge wie quicktype und typescript-json-schema erzeugen Schemas aus bestehenden Typen. Die Ausgabe lässt meist zu viel zu: jedes Feld optional, additionalProperties offen. Behandeln Sie generierte Schemas als Entwürfe, ziehen Sie sie von Hand fest und richten Sie eine CI ein, die echte Produktions-Samples gegen das Schema validiert (und umgekehrt), damit Drift schnell sichtbar wird.
Performance: Zahlen und Faustregeln
- Ajv (Node.js): Kompilierte Validatoren erledigen eine Prüfung in deutlich unter einer Mikrosekunde. Der schnellste produktionsreife JS-Validator.
jsonschema(Python): Interpretiert, 10–100× langsamer als Pydantic. Tauschen Sie auffastjsonschema, wenn das ins Gewicht fällt; es generiert Python-Code und liegt nahe an Ajv.- Rust und Go:
jsonschema-rsundxeipuuv/gojsonschemaliefern weitere 2–5× gegenüber Ajv auf der Gateway-Ebene. - Der mit Abstand größte Hebel ist das Vorkompilieren.
ajv.compile(schema)einmal beim Modul-Laden, den zurückgegebenen Validator bei jeder Anfrage wiederverwenden. Erneutes Kompilieren pro Anfrage drückt den Durchsatz um Faktor 50 oder mehr.
Häufig gestellte Fragen
Was ist JSON-Schema-Validierung in einfachen Worten?
JSON-Schema-Validierung prüft, ob ein JSON-Dokument einem Vertrag folgt. Der Vertrag (das Schema) ist selbst JSON und deklariert Typen, Pflichtfelder und Einschränkungen. Ein Validator liest Schema und Daten ein und meldet entweder „erfolgreich” oder die Pfade, die fehlgeschlagen sind, samt Grund.
Wie validiere ich JSON online gegen ein Schema?
Fügen Sie Schema und Daten in den Playground von ajv.js.org oder bei jsonschemavalidator.net ein und Sie erhalten sofort ein Urteil. Wenn das JSON ungültig aussieht, säubern Sie es zuerst im JSON-Formatierer; beide laufen im Browser, kein Upload.
Welcher JSON-Schema-Validator ist 2026 der schnellste?
In Node erledigt Ajv mit vorkompilierten Validatoren eine Prüfung in unter einer Mikrosekunde. In Python erreicht fastjsonschema durch Code-Generierung Ajv-Klasse-Durchsatz. Auf Gateway-Ebene sind jsonschema-rs (Rust) und gojsonschema (Go) 2–5× schneller als Ajv. Was auch immer Sie wählen: einmal vorkompilieren und wiederverwenden.
Was ist der Unterschied zwischen JSON Schema und TypeScript-Typen?
TypeScript prüft den Code, den Sie schreiben, zur Übersetzungszeit. JSON Schema prüft unbekanntes JSON zur Laufzeit. TypeScript sieht JSON nicht, das aus einer HTTP-Antwort, einer Datei oder einem Nutzer-Paste kommt; genau dafür ist JSON Schema da.
Sollte ich Draft 2020-12 oder Draft 7 nehmen?
Für neue Projekte 2026 wählen Sie Draft 2020-12. prefixItems, unevaluatedProperties und $dynamicRef lösen reale Probleme. OpenAPI 3.1 nutzt 2020-12 nativ. Bleiben Sie nur bei Draft 7, wenn Sie Postman-Kompatibilität oder ältere Dienste bedienen müssen. OpenAPI 3.0 verwendet eine Draft-4-Teilmenge; mischen Sie Dialekte nicht.
Wie generiere ich ein JSON Schema aus vorhandenem JSON?
Drei Optionen: Samples in quicktype.io oder jsonschema.net einfügen; auf der Kommandozeile npx genson-js oder pip install genson && genson sample.json ausführen; oder von Hand schreiben. Automatisch generierte Schemas sind zu permissiv (jedes Feld optional, additionalProperties: true), also ziehen Sie sie immer fest, bevor Sie sie als Verträge behandeln.
Kann JSON Schema OpenAPI ersetzen?
Nein. OpenAPI nutzt JSON Schema intern, um Request- und Response-Bodies zu beschreiben, und ergänzt anschließend Pfade, Security-Schemas, Parameter und Server-URLs. Beide ergänzen sich: Schreiben Sie Ihre Schemas, referenzieren Sie sie aus einem OpenAPI-Dokument und Sie erhalten vollständige API-Verträge.
Ist JSON Schema dasselbe wie JSONPath oder jq?
Verschiedene Probleme. JSON Schema validiert die Struktur („erfüllt dieses JSON den Vertrag?”). JSONPath und jq extrahieren Werte („jeder Pod-Name in der Phase Running”). Validieren Sie mit einem Schema; abfragen Sie mit JSONPath oder jq.
Warum besteht meine Ajv-Validierung, aber die Produktion lehnt die Daten ab?
Drei Schuldige decken fast jeden Fall ab: vergessenes ajv-formats, sodass format: "email" nie validiert hat; weggelassenes additionalProperties: false, sodass zusätzliche Client-Felder durchrutschen; oder additionalProperties: false innerhalb von allOf oder oneOf und die Erkenntnis, dass es nicht komponiert. Wechseln Sie zu unevaluatedProperties: false.
Kann ich JSON-Schema-Fehlermeldungen für Endnutzer anpassen?
Ja. In Node installieren Sie ajv-errors, um errorMessage direkt im Schema einzubetten, und ajv-i18n für Übersetzungen in über 30 Locales. In Python legt jsonschema den vollständigen Validierungskontext an jedem Fehlerobjekt offen, sodass Sie Fehlertyp plus Pfad auf den Text abbilden können, den Ihr Designsystem vorsieht.