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 Team
• Technical WriterExpert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.
# 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!
Artículos Relacionados
¿Qué es JSON? Guía Completa para Principiantes
Descubre qué es JSON, por qué es importante y cómo funciona. Una guía completa para principiantes sobre el formato de datos más popular de la web.
Python y JSON: Guía Completa del Módulo json
Aprende a trabajar con JSON en Python usando el módulo json. Incluye parsing, serialización, archivos JSON y mejores prácticas.
JavaScript y JSON: Guía Completa de JSON.parse() y JSON.stringify()
Domina el trabajo con JSON en JavaScript. Aprende JSON.parse(), JSON.stringify() y mejores prácticas para aplicaciones web modernas.