Clase 09 — Validación, Errores Comunes y Buenas Prácticas
Herramientas de validación
# jq (la más usada)
jq empty archivo.json && echo "✅ Válido" || echo "❌ Inválido"
# python3
python3 -m json.tool archivo.json
python3 -c "import json; json.load(open('archivo.json'))" && echo "✅" || echo "❌"
# jsonlint (Node.js)
npm install -g jsonlint
jsonlint archivo.json
Validar en CI/CD
name: JSON Lint
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validar todos los JSON
run: |
errores=0
for f in $(find . -name "*.json" -not -path "./node_modules/*"); do
if ! jq empty "$f" 2>/dev/null; then
echo "❌ JSON inválido: $f"; ((errores++))
else
echo "✅ $f"
fi
done
[[ $errores -gt 0 ]] && exit 1
Errores comunes
1. Coma trailing
// ❌ ERROR
{ "nombre": "Ana", "edad": 28, }
// ✅ CORRECTO
{ "nombre": "Ana", "edad": 28 }
2. Comillas simples
// ❌ ERROR
{ 'nombre': 'Ana' }
// ✅ CORRECTO
{ "nombre": "Ana" }
3. Claves sin comillas
// ❌ ERROR (esto es JavaScript, no JSON)
{ nombre: "Ana" }
// ✅ CORRECTO
{ "nombre": "Ana" }
4. Comentarios
// ❌ ERROR — JSON no soporta comentarios
{ "nombre": "Ana" /* comentario */ }
// ✅ ALTERNATIVA — Campo de documentación
{ "_comment": "Configuración del servidor", "nombre": "Ana" }
5. Strings multilínea
// ❌ ERROR
{ "mensaje": "línea 1
línea 2" }
// ✅ CORRECTO — Usar \n
{ "mensaje": "línea 1\nlínea 2" }
6. Valores no válidos
// ❌ ERROR: undefined, Infinity, NaN, funciones
// ✅ CORRECTO: usar null en su lugar
7. Encoding BOM
# Detectar BOM
file archivo.json
# Remover BOM
sed -i '1s/^\xEF\xBB\xBF//' archivo.json
Buenas prácticas
1. Indentación de 2 espacios
2. Nombres de claves consistentes
// ✅ snake_case (común en Python, APIs REST)
{ "user_name": "ana", "created_at": "2026-02-20" }
// ✅ camelCase (común en JavaScript)
{ "userName": "ana", "createdAt": "2026-02-20" }
// ❌ EVITAR mezclar estilos
3. Usar tipos apropiados
// ❌ Tipos incorrectos
{ "puerto": "8080", "activo": "true" }
// ✅ Tipos correctos
{ "puerto": 8080, "activo": true }
4. Fechas en formato ISO 8601
{ "creado": "2026-02-20T15:30:00Z" }
5. Respuestas de API consistentes
// Éxito
{ "status": "success", "code": 200, "data": { "id": 1, "nombre": "Pikachu" } }
// Error
{ "status": "error", "code": 404, "error": { "message": "Pokémon no encontrado" } }
6. JSON Schema para validar estructura
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Servidor",
"type": "object",
"required": ["hostname", "ip", "puerto"],
"properties": {
"hostname": { "type": "string", "pattern": "^[a-z][a-z0-9-]+$" },
"ip": { "type": "string", "format": "ipv4" },
"puerto": { "type": "integer", "minimum": 1, "maximum": 65535 },
"ssl": { "type": "boolean", "default": false }
}
}
Cheat Sheet — Referencia rápida
TIPOS: "string" | 42 | 3.14 | true/false | null | {} | []
REGLAS: ✅ Comillas dobles | ✅ Coma entre elementos | ❌ Sin comentarios | ❌ Sin coma trailing
jq BÁSICO:
jq '.' → Pretty print
jq '.campo' → Acceder campo
jq '.[0]' → Primer elemento
jq '.[]' → Iterar array
jq 'length' → Longitud
jq 'keys' → Listar claves
jq 'map(.campo)' → Transformar
jq 'select(.x == "y")' → Filtrar
jq 'sort_by(.campo)' → Ordenar
jq 'group_by(.campo)' → Agrupar
jq -r → Sin comillas
jq -c → Compacto
jq empty → Solo validar