Ratgeber · JSON Schema 2020-12
JSON-Schema-Basics: type, properties und required richtig nutzen
type definiert primitive Typen. properties beschreibt Objekt-Felder. required listet Pflichtfelder. additionalProperties muss explizit gesetzt werden.
Von Mateusz Viola
Betreiber & redaktionelle Verantwortung json-validator.de
Veröffentlicht
Aktualisiert:
Die drei zentralen Object-Keywords
JSON-Objekte werden mit drei Keywords beschrieben: type, properties, required. Diese Kombination deckt 80 % aller praktischen Use-Cases ab.
type
type legt den Datentyp fest. Werte: "string", "number", "integer", "boolean", "object", "array", "null". Auch ein Array möglicher Typen ist erlaubt:
{ "type": "string" } // muss String sein
{ "type": ["string", "null"] } // String oder null (nullable)
{ "type": "integer" } // Ganzzahl, nicht 3.14
Wichtige Unterscheidung: "integer" ist ein eigener Typ, nicht ein Subset von "number". Wenn beide passen sollen: "type": ["number", "integer"] - aber das ist redundant, da integer ⊂ number gilt.
properties
properties ist die Beschreibung der Felder eines Objekts. Keys sind die Feldnamen, Values sind selbst Sub-Schemas:
{
"type": "object",
"properties": {
"name": { "type": "string", "minLength": 1 },
"age": { "type": "integer", "minimum": 0 }
}
}
Wichtig: properties macht keine Felder zur Pflicht. Wenn properties nur eine Erwartung definiert, ist das Objekt {} ohne Felder erst mal valide.
required
required ist ein Array von Strings - KEIN Objekt. Stehen Feldnamen darin, müssen sie im validierten Objekt vorhanden sein:
{
"type": "object",
"required": ["name", "email"],
"properties": {
"name": { "type": "string" },
"email": { "type": "string", "format": "email" }
}
}
Typischer Anfänger-Fehler:
// FALSCH
{ "required": { "name": true } }
// RICHTIG
{ "required": ["name"] }
additionalProperties - die unterschätzte vierte Säule
Per Default sind Felder die NICHT in properties stehen, erlaubt. Das ist meist nicht gewollt - Tippfehler im Client werden so still durchgewunken.
{
"type": "object",
"required": ["email"],
"properties": {
"email": { "type": "string", "format": "email" }
},
"additionalProperties": false
}
Damit wirft { "emial": "test@example.com" } einen klaren Validation-Error: "must NOT have additional property 'emial'".
patternProperties - für dynamische Keys
Wenn die Keys eines Objekts nicht statisch sind (z.B. ein Map-Typ):
{
"type": "object",
"patternProperties": {
"^[A-Z]{2}$": {
"type": "number",
"minimum": 0,
"maximum": 1
}
},
"additionalProperties": false
}
Damit passt jedes Objekt wo alle Keys zwei Großbuchstaben sind und alle Werte Zahlen zwischen 0 und 1 (z.B. Wahrscheinlichkeits-Map pro Länder-Code).
minProperties / maxProperties
Begrenzt die Anzahl der Felder im Objekt:
{ "type": "object", "minProperties": 1, "maxProperties": 10 }
Selten direkt nützlich, aber bei dynamischen Maps relevant.
Anti-Pattern: alles in einem Riesen-Schema
Wenn du dein Schema-File auf 800+ Zeilen hast, ist es Zeit für $defs und $ref. Lokale Wiederverwendung:
{
"$defs": {
"Address": {
"type": "object",
"required": ["street", "city"],
"properties": {
"street": { "type": "string" },
"city": { "type": "string" }
}
}
},
"type": "object",
"properties": {
"billing": { "$ref": "#/$defs/Address" },
"shipping": { "$ref": "#/$defs/Address" }
}
}
Schema testen
Im Validator oben kannst du dein Schema einsetzen, ein Test-Payload danebenstellen und sofort sehen welche Constraints verletzt werden. Mehrere Iterationen gehen schnell - schneller als jede TDD-Schleife im Backend-Code.