← Volver al Blog

Entendiendo JSON Schema: Validación y Documentación de Datos

Aprende a usar JSON Schema para validar y documentar tus estructuras JSON. Guía completa con ejemplos prácticos en JavaScript y Python.

Big JSON Team15 min de lecturaAvanzado
B

Big JSON Team

Technical Writer

Expert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.

15 min lectura

# Entendiendo JSON Schema: Validación y Documentación de Datos

JSON Schema es un vocabulario poderoso que te permite anotar y validar documentos JSON. Esta guía completa te enseñará todo sobre JSON Schema desde lo básico hasta técnicas avanzadas.

¿Qué es JSON Schema?

JSON Schema es un estándar para describir la estructura, contenido y semántica de datos JSON. Funciona como un contrato que define:

  • ✅ Qué propiedades son requeridas
  • ✅ Qué tipos de datos son permitidos
  • ✅ Restricciones de valores (mínimo, máximo, longitud, etc.)
  • ✅ Patrones de validación
  • ✅ Valores por defecto

Schema Básico

Estructura Fundamental

{

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

"$id": "https://ejemplo.com/schemas/usuario.json",

"title": "Usuario",

"description": "Schema para validar datos de usuario",

"type": "object",

"properties": {

"nombre": {

"type": "string",

"description": "Nombre completo del usuario"

},

"edad": {

"type": "integer",

"minimum": 0,

"maximum": 150

},

"email": {

"type": "string",

"format": "email"

}

},

"required": ["nombre", "email"]

}

Tipos de Datos

{

"type": "object",

"properties": {

"cadena": {

"type": "string"

},

"numero": {

"type": "number"

},

"entero": {

"type": "integer"

},

"booleano": {

"type": "boolean"

},

"arreglo": {

"type": "array"

},

"objeto": {

"type": "object"

},

"nulo": {

"type": "null"

}

}

}

Validación de Strings

Restricciones de Longitud

{

"type": "object",

"properties": {

"username": {

"type": "string",

"minLength": 3,

"maxLength": 20,

"description": "Nombre de usuario entre 3 y 20 caracteres"

},

"password": {

"type": "string",

"minLength": 8,

"description": "Contraseña de al menos 8 caracteres"

}

}

}

Patrones con Expresiones Regulares

{

"type": "object",

"properties": {

"telefono": {

"type": "string",

"pattern": "^\+?[1-9]\d{1,14}$",

"description": "Número de teléfono en formato E.164"

},

"codigoPostal": {

"type": "string",

"pattern": "^\d{5}$",

"description": "Código postal español de 5 dígitos"

},

"nif": {

"type": "string",

"pattern": "^[0-9]{8}[A-Z]$",

"description": "NIF español"

}

}

}

Formatos Predefinidos

{

"type": "object",

"properties": {

"email": {

"type": "string",

"format": "email"

},

"website": {

"type": "string",

"format": "uri"

},

"fechaNacimiento": {

"type": "string",

"format": "date"

},

"ultimaConexion": {

"type": "string",

"format": "date-time"

},

"ipv4": {

"type": "string",

"format": "ipv4"

},

"ipv6": {

"type": "string",

"format": "ipv6"

}

}

}

Validación de Numbers

Rangos y Múltiplos

{

"type": "object",

"properties": {

"edad": {

"type": "integer",

"minimum": 0,

"maximum": 150

},

"precio": {

"type": "number",

"minimum": 0,

"exclusiveMinimum": true,

"description": "Precio mayor que 0"

},

"descuento": {

"type": "number",

"minimum": 0,

"maximum": 100,

"multipleOf": 5,

"description": "Descuento en múltiplos de 5%"

}

}

}

Validación de Arrays

Estructura Básica

{

"type": "object",

"properties": {

"tags": {

"type": "array",

"items": {

"type": "string"

},

"minItems": 1,

"maxItems": 10,

"uniqueItems": true,

"description": "Entre 1 y 10 tags únicos"

}

}

}

Arrays con Tipos Mixtos

{

"coordenadas": {

"type": "array",

"items": [

{

"type": "number",

"description": "Latitud"

},

{

"type": "number",

"description": "Longitud"

}

],

"minItems": 2,

"maxItems": 2

}

}

Arrays de Objetos

{

"usuarios": {

"type": "array",

"items": {

"type": "object",

"properties": {

"id": {

"type": "integer"

},

"nombre": {

"type": "string"

}

},

"required": ["id", "nombre"]

}

}

}

Objetos Anidados

Schema Complejo

{

"type": "object",

"properties": {

"usuario": {

"type": "object",

"properties": {

"nombre": {

"type": "string"

},

"direccion": {

"type": "object",

"properties": {

"calle": {

"type": "string"

},

"ciudad": {

"type": "string"

},

"codigoPostal": {

"type": "string",

"pattern": "^\d{5}$"

}

},

"required": ["calle", "ciudad", "codigoPostal"]

}

},

"required": ["nombre", "direccion"]

}

}

}

Propiedades Adicionales

Controlar Propiedades Extra

{

"type": "object",

"properties": {

"nombre": {

"type": "string"

},

"edad": {

"type": "integer"

}

},

"additionalProperties": false,

"description": "Solo nombre y edad son permitidos"

}

Propiedades Adicionales con Schema

{

"type": "object",

"properties": {

"nombre": {

"type": "string"

}

},

"additionalProperties": {

"type": "string"

},

"description": "Propiedades adicionales deben ser strings"

}

Enumeraciones y Constantes

Valores Permitidos

{

"type": "object",

"properties": {

"estado": {

"type": "string",

"enum": ["activo", "inactivo", "pendiente"],

"description": "Estado del usuario"

},

"rol": {

"type": "string",

"enum": ["admin", "editor", "usuario"]

},

"prioridad": {

"type": "integer",

"enum": [1, 2, 3, 4, 5]

}

}

}

Valores Constantes

{

"type": "object",

"properties": {

"version": {

"const": "1.0.0",

"description": "Versión fija del schema"

},

"tipo": {

"const": "usuario"

}

}

}

Composición de Schemas

allOf (AND lógico)

{

"allOf": [

{

"type": "object",

"properties": {

"nombre": {

"type": "string"

}

},

"required": ["nombre"]

},

{

"type": "object",

"properties": {

"email": {

"type": "string",

"format": "email"

}

},

"required": ["email"]

}

]

}

anyOf (OR lógico)

{

"anyOf": [

{

"type": "object",

"properties": {

"email": {

"type": "string",

"format": "email"

}

},

"required": ["email"]

},

{

"type": "object",

"properties": {

"telefono": {

"type": "string"

}

},

"required": ["telefono"]

}

],

"description": "Debe tener email o teléfono"

}

oneOf (XOR lógico)

{

"oneOf": [

{

"type": "object",

"properties": {

"tipoPago": {

"const": "tarjeta"

},

"numeroTarjeta": {

"type": "string"

}

},

"required": ["tipoPago", "numeroTarjeta"]

},

{

"type": "object",

"properties": {

"tipoPago": {

"const": "transferencia"

},

"iban": {

"type": "string"

}

},

"required": ["tipoPago", "iban"]

}

]

}

Validación en JavaScript

Usando Ajv

const Ajv = require('ajv');

const addFormats = require('ajv-formats');

// Crear instancia de validador

const ajv = new Ajv({ allErrors: true });

addFormats(ajv);

// Definir schema

const schema = {

type: 'object',

properties: {

nombre: {

type: 'string',

minLength: 2

},

email: {

type: 'string',

format: 'email'

},

edad: {

type: 'integer',

minimum: 18

}

},

required: ['nombre', 'email']

};

// Compilar schema

const validate = ajv.compile(schema);

// Validar datos

const datosValidos = {

nombre: 'Ana García',

email: 'ana@ejemplo.com',

edad: 28

};

if (validate(datosValidos)) {

console.log('✓ Datos válidos');

} else {

console.log('✗ Errores:', validate.errors);

}

// Datos inválidos

const datosInvalidos = {

nombre: 'A', // Muy corto

email: 'no-es-email', // Formato inválido

edad: 15 // Menor que mínimo

};

if (!validate(datosInvalidos)) {

console.log('Errores encontrados:');

validate.errors.forEach(error => {

console.log(- ${error.instancePath}: ${error.message});

});

}

Mensajes de Error Personalizados

const Ajv = require('ajv');

const ajv = new Ajv({ allErrors: true });

require('ajv-errors')(ajv);

const schema = {

type: 'object',

properties: {

username: {

type: 'string',

minLength: 3,

maxLength: 20

},

password: {

type: 'string',

minLength: 8

}

},

required: ['username', 'password'],

errorMessage: {

properties: {

username: 'El nombre de usuario debe tener entre 3 y 20 caracteres',

password: 'La contraseña debe tener al menos 8 caracteres'

},

required: {

username: 'El nombre de usuario es requerido',

password: 'La contraseña es requerida'

}

}

};

const validate = ajv.compile(schema);

const datos = { username: 'ab' };

validate(datos);

console.log(validate.errors);

Validación en Python

Usando jsonschema

from jsonschema import validate, ValidationError

import json

# Definir schema

schema = {

"type": "object",

"properties": {

"nombre": {

"type": "string",

"minLength": 2

},

"email": {

"type": "string",

"format": "email"

},

"edad": {

"type": "integer",

"minimum": 18

}

},

"required": ["nombre", "email"]

}

# Datos válidos

datos_validos = {

"nombre": "Carlos López",

"email": "carlos@ejemplo.com",

"edad": 30

}

try:

validate(instance=datos_validos, schema=schema)

print("✓ Datos válidos")

except ValidationError as e:

print(f"✗ Error: {e.message}")

# Datos inválidos

datos_invalidos = {

"nombre": "C",

"email": "no-es-email"

}

try:

validate(instance=datos_invalidos, schema=schema)

except ValidationError as e:

print(f"Error en {e.path}: {e.message}")

Validador Personalizado

from jsonschema import validate, ValidationError, Draft7Validator

from jsonschema.exceptions import best_match

def validar_datos(datos, schema):

"""Validar datos con mensajes de error mejorados"""

validator = Draft7Validator(schema)

errors = sorted(validator.iter_errors(datos), key=lambda e: e.path)

if errors:

errores_formateados = []

for error in errors:

path = '.'.join(str(p) for p in error.path)

errores_formateados.append({

'campo': path or 'raíz',

'mensaje': error.message,

'valor': error.instance

})

return False, errores_formateados

return True, []

# Uso

schema = {

"type": "object",

"properties": {

"nombre": {"type": "string"},

"edad": {"type": "integer", "minimum": 0}

},

"required": ["nombre"]

}

datos = {"edad": -5}

valido, errores = validar_datos(datos, schema)

if not valido:

for error in errores:

print(f"{error['campo']}: {error['mensaje']}")

Schemas Reutilizables

Definiciones y Referencias

{

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

"definitions": {

"direccion": {

"type": "object",

"properties": {

"calle": {"type": "string"},

"ciudad": {"type": "string"},

"codigoPostal": {"type": "string"}

},

"required": ["calle", "ciudad"]

},

"contacto": {

"type": "object",

"properties": {

"email": {"type": "string", "format": "email"},

"telefono": {"type": "string"}

}

}

},

"type": "object",

"properties": {

"nombre": {"type": "string"},

"direccionCasa": {

"$ref": "#/definitions/direccion"

},

"direccionTrabajo": {

"$ref": "#/definitions/direccion"

},

"contacto": {

"$ref": "#/definitions/contacto"

}

}

}

Referencias Externas

{

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

"type": "object",

"properties": {

"usuario": {

"$ref": "https://ejemplo.com/schemas/usuario.json"

},

"pedido": {

"$ref": "https://ejemplo.com/schemas/pedido.json"

}

}

}

Casos de Uso Prácticos

API Request Validation

const express = require('express');

const Ajv = require('ajv');

const app = express();

const ajv = new Ajv();

app.use(express.json());

// Schema para crear usuario

const crearUsuarioSchema = {

type: 'object',

properties: {

nombre: { type: 'string', minLength: 2 },

email: { type: 'string', format: 'email' },

password: { type: 'string', minLength: 8 }

},

required: ['nombre', 'email', 'password'],

additionalProperties: false

};

const validateCrearUsuario = ajv.compile(crearUsuarioSchema);

app.post('/usuarios', (req, res) => {

if (!validateCrearUsuario(req.body)) {

return res.status(400).json({

error: 'Datos inválidos',

detalles: validateCrearUsuario.errors

});

}

// Procesar datos válidos

res.json({ mensaje: 'Usuario creado', datos: req.body });

});

app.listen(3000);

Archivo de Configuración

{

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

"title": "Configuración de Aplicación",

"type": "object",

"properties": {

"servidor": {

"type": "object",

"properties": {

"puerto": {

"type": "integer",

"minimum": 1024,

"maximum": 65535,

"default": 3000

},

"host": {

"type": "string",

"default": "localhost"

}

}

},

"baseDatos": {

"type": "object",

"properties": {

"tipo": {

"enum": ["mysql", "postgresql", "mongodb"]

},

"host": {

"type": "string"

},

"puerto": {

"type": "integer"

}

},

"required": ["tipo", "host"]

},

"logs": {

"type": "object",

"properties": {

"nivel": {

"enum": ["debug", "info", "warn", "error"]

},

"archivo": {

"type": "string"

}

}

}

},

"required": ["servidor", "baseDatos"]

}

Mejores Prácticas

1. Usa Descripciones Claras

{

"properties": {

"edad": {

"type": "integer",

"minimum": 0,

"maximum": 150,

"description": "Edad del usuario en años. Debe ser un número entero entre 0 y 150."

}

}

}

2. Define Valores por Defecto

{

"properties": {

"idioma": {

"type": "string",

"enum": ["es", "en", "fr"],

"default": "es",

"description": "Idioma preferido del usuario"

}

}

}

3. Valida en el Cliente y Servidor

// Cliente (React)

import Ajv from 'ajv';

function FormularioUsuario() {

const ajv = new Ajv();

const validate = ajv.compile(usuarioSchema);

const handleSubmit = (datos) => {

if (!validate(datos)) {

mostrarErrores(validate.errors);

return;

}

// Enviar al servidor

enviarDatos(datos);

};

}

// Servidor (Express)

app.post('/usuarios', (req, res) => {

// Validar de nuevo en el servidor

if (!validate(req.body)) {

return res.status(400).json({ errors: validate.errors });

}

// Procesar

});

4. Versionado de Schemas

{

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

"$id": "https://ejemplo.com/schemas/usuario/v2.json",

"version": "2.0.0",

"type": "object",

"properties": {

"schemaVersion": {

"const": "2.0.0"

}

}

}

Herramientas Útiles

Generadores de Schema

  • quicktype.io - Generar schemas desde JSON
  • jsonschema.net - Editor visual de schemas
  • Big JSON Viewer - Validar con schemas grandes

Validadores Online

  • jsonschemalint.com - Validar JSON contra schema
  • jsonschemavalidator.net - Validación y testing

Conclusión

JSON Schema es una herramienta esencial para validar y documentar estructuras JSON. Te permite crear contratos claros entre sistemas y asegurar la integridad de datos.

Puntos Clave

  • Define tipos, rangos y patrones de validación
  • Usa composición (allOf, anyOf, oneOf) para schemas complejos
  • Valida tanto en cliente como servidor
  • Aprovecha referencias para reutilizar definiciones
  • Documenta con descripciones claras

¡Comienza a usar JSON Schema para crear APIs más robustas!

Share:

Artículos Relacionados

Read in English