JSON Schema - Exemples

Exemple 1: Esquema bàsic

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "nom": { "type": "string" },
    "edat": { "type": "integer" }
  },
  "required": ["nom", "edat"],
  "additionalProperties": false
}

Què comprova este esquema

  • El JSON ha de ser un objecte.
  • Ha de tindre nom (string) i edat (integer).
  • Si falta algun dels dos camps, falla.
  • No permet propietats extra.

Exemple vàlid

{ "nom": "Anna", "edat": 25 }

Exemple invàlid

{ "nom": "Anna" }

Exemple 2: Esquema amb arrays, enums, patterns i nulls

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "coordinades": {
      "type": "array",
      "items": { "type": "number" },
      "minItems": 2,
      "maxItems": 2
    },
    "tipus": {
      "type": "string",
      "enum": ["Punt"]
    },
    "dataCreacio": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
    },
    "descripcio": {
      "type": ["string", "null"]
    }
  },
  "required": ["coordinades", "tipus"],
  "additionalProperties": false
}

Què comprova este esquema

  • El JSON ha de ser un objecte.
  • coordinades ha de ser un array de 2 números exactes.
  • tipus ha de ser un string i només pot ser "Punt" (enum).
  • dataCreacio és opcional, però si apareix ha de tindre format AAAA-MM-DD (pattern).
  • descripcio és opcional i pot ser text o null.
  • No permet propietats extra.

Exemple vàlid

{
  "coordinades": [10.5, 20.3],
  "tipus": "Punt",
  "dataCreacio": "2024-05-17",
  "descripcio": null
}

Exemple invàlid

{
  "coordinades": [10.5, "20.3"],
  "tipus": "Punt"
}

Exemple 3: Esquema complet amb reutilització (definitions i $ref)

A continuació tenim un esquema complet que combina els punts principals: validació d’objectes, arrays, enums, patrons, restriccions de longitud i rang, valors null i reutilització amb $ref.

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",

  "definitions": {
    "Persona": {
      "type": "object",
      "properties": {
        "nom": {
          "type": "string",
          "minLength": 3,
          "maxLength": 30
        },
        "edat": {
          "type": "integer",
          "minimum": 0,
          "maximum": 120
        }
      },
      "required": ["nom", "edat"],
      "additionalProperties": false
    }
  },

  "properties": {
    "coordinades": {
      "type": "array",
      "items": { "type": "number" },
      "minItems": 2,
      "maxItems": 2
    },
    "tipus": {
      "type": "string",
      "enum": ["Punt"]
    },
    "dataCreacio": {
      "type": "string",
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
    },
    "responsable": {
      "$ref": "#/definitions/Persona"
    },
    "descripcio": {
      "type": ["string", "null"]
    }
  },

  "required": ["coordinades", "tipus", "responsable"],
  "additionalProperties": false
}

Què valida este esquema

Hem de tindre en compte que un JSON Schema és un contracte: no canvia dades, només comprova que la forma i les regles es complixen.

Este esquema obliga a:

  • Un objecte com a document principal.
  • Les propietats obligatòries: coordinades, tipus, responsable.
  • Cap propietat extra fora de les definides.
  • Un array de dos números en coordinades.
  • Un valor fix per a tipus (només "Punt").
  • Un format de data en dataCreacio (si apareix).
  • Un objecte responsable amb estructura definida per un subesquema reutilitzable.
  • Una descripcio que pot ser text o null.

Explicació pas a pas

$schema

"$schema": "http://json-schema.org/draft-07/schema#"

Esta línia indica la versió de l’estàndard que estem usant.

  • No valida dades directament.
  • Serveix perquè la ferramenta sàpia quines normes ha d’aplicar.

type: "object" (document principal)

"type": "object"

Açò obliga que el JSON siga un objecte:

  • Ha de començar per { }.
  • Si fora un array [] o un string, fallaria.

Reutilització d’esquemes amb definitions i $ref

Quan un esquema creix, és habitual no repetir estructures.

Hem de tindre en compte que:

  • definitions guarda subesquemes amb un nom.
  • $ref reutilitza eixos subesquemes.

definitions (subesquema Persona)

"definitions": {
  "Persona": { ... }
}

Ací definim una estructura reutilitzable anomenada "Persona".

Dins de Persona

1) properties

"properties": {
  "nom": { ... },
  "edat": { ... }
}

Defineix els camps que pot tindre una persona.

2) Restriccions en nom

"nom": {
  "type": "string",
  "minLength": 3,
  "maxLength": 30
}
  • Ha de ser string.
  • Ha de tindre entre 3 i 30 caràcters.

3) Restriccions en edat

"edat": {
  "type": "integer",
  "minimum": 0,
  "maximum": 120
}
  • Ha de ser integer.
  • Ha d’estar entre 0 i 120.

4) required dins de Persona

"required": ["nom", "edat"]

Obliga que una persona tinga els dos camps.

5) additionalProperties: false dins de Persona

"additionalProperties": false

No permet camps extra com "altura" o "dni" si no estan definits.


$ref (usar Persona dins del document principal)

"responsable": {
  "$ref": "#/definitions/Persona"
}

Açò significa:

  • responsable ha de complir exactament el subesquema Persona.
  • #/definitions/Persona és una referència interna (dins del mateix document).

properties del document principal

"properties": { ... }

Defineix els camps que pot tindre el JSON principal.

Hem de tindre en compte una idea clau:

  • properties descriu com han de ser si apareixen.
  • required dirà quins han d’aparéixer sí o sí.

coordinades (array amb restriccions)

"coordinades": {
  "type": "array",
  "items": { "type": "number" },
  "minItems": 2,
  "maxItems": 2
}

Açò obliga a:

  • Ser un array.
  • Tindre elements de tipus number.
  • Tindre exactament 2 elements (mínim 2 i màxim 2).

Per tant:

  • [10.5, 20.3] seria correcte.
  • [10.5] seria incorrecte (massa curt).
  • [10.5, 20.3, 30] seria incorrecte (massa llarg).
  • [10.5, "20.3"] seria incorrecte (tipus incorrecte).

tipus (enum)

"tipus": {
  "type": "string",
  "enum": ["Punt"]
}

Açò obliga a:

  • Ser string.
  • Ser exactament "Punt".

Qualsevol altra cosa falla: "punt", "PUNt", "Linea".


dataCreacio (pattern)

"dataCreacio": {
  "type": "string",
  "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
}

Açò valida la forma AAAA-MM-DD.

Hem de tindre en compte:

  • ^ indica inici del text.
  • $ indica final del text.
  • \\d representa un dígit (0-9), però en JSON s’escriu amb doble barra.
  • {4} i {2} indiquen quantitat de repeticions.

Per tant:

  • "2024-05-17" passaria.
  • "2024/05/17" fallaria.
  • "2024-5-7" fallaria.

descripcio (permetre null)

"descripcio": {
  "type": ["string", "null"]
}

Açò permet:

  • Un text
  • O null

És útil quan un camp pot estar buit però volem expressar-ho explícitament.


required del document principal

"required": ["coordinades", "tipus", "responsable"]

Obliga que existisquen estos tres camps.

Hem de tindre en compte que:

  • dataCreacio i descripcio poden no aparéixer.
  • Si apareixen, han de complir les seues regles.

additionalProperties: false (document principal)

"additionalProperties": false

No permet cap camp extra fora dels definits en properties.

Per exemple, si apareix "color": "roig", fallaria.


Exemple de dades vàlides

{
  "coordinades": [10.5, 20.3],
  "tipus": "Punt",
  "dataCreacio": "2024-05-17",
  "responsable": {
    "nom": "Anna",
    "edat": 25
  },
  "descripcio": null
}

Hem de tindre en compte que:

  • coordinades té 2 números.
  • tipus és exactament "Punt".
  • dataCreacio complix el format.
  • responsable complix el subesquema Persona.
  • descripcio pot ser null.

Exemple de dades invàlides

{
  "coordinades": [10.5],
  "tipus": "Linea",
  "responsable": {
    "nom": "An",
    "edat": 200,
    "extra": true
  }
}

Falla per diversos motius:

  • coordinades té només 1 element i en necessitem 2.
  • tipus no està dins de enum.
  • nom té menys de 3 caràcters.
  • edat supera el màxim 120.
  • extra no està permés per additionalProperties: false dins de Persona.