JSON RFC 8259: detalles sutiles que hacen tropezar a los parsers de producción
JSON es más pequeño de lo que crees
La gramática JSON de la RFC 8259 es diminuta: objetos, arrays, cadenas, números y los tres literales true, false y null. Esa simplicidad es por la que está en todas partes — y también por la que dos sorpresas pillan a la gente desprevenida. Primero, cualquier valor puede ser el documento entero: 42, "hello" y true son cada uno JSON completo y válido. La RFC 4627 más antigua exigía que el nivel superior fuera un objeto o array, así que algunas herramientas heredadas aún rechazan un valor suelto.
Segundo, la especificación deja deliberadamente varios comportamientos sin especificar. Define la sintaxis con precisión pero dice poco sobre claves duplicadas, precisión numérica u orden. Los parsers de producción rellenan esos huecos de forma distinta, y ahí es exactamente donde viven los fallos de interoperabilidad.
Claves duplicadas: comportamiento indefinido
La RFC 8259 dice que los nombres de objeto DEBERÍAN (SHOULD) ser únicos, no que DEBEN (MUST) serlo. Cuando una clave se repite, el resultado no está especificado, así que los parsers divergen: la mayoría toma el último valor, algunos conservan el primero, unos pocos lanzan error y alguno raro conserva ambos. Ninguno es incorrecto según la especificación.
Es un riesgo de seguridad real. Si un servicio valida {"role":"user","role":"admin"} leyendo el primer role y otro actúa sobre el último, un atacante puede colar un privilegio saltándose la validación. Trata las claves duplicadas como error donde la decisión importe, y nunca dependas de qué valor 'gana'.
Números: no hay enteros, solo problemas
JSON tiene un único tipo de número. La RFC no define precisión ni rango — solo señala que, por interoperabilidad, se espera que las implementaciones manejen valores que quepan en doble precisión IEEE 754. En la práctica eso significa que cualquier cosa por encima de 2^53 (es decir, 9007199254740992) puede perder precisión.
El fallo clásico: un ID de 64 bits como 9007199254740993 se convierte en 9007199254740992 tras JSON.parse en JavaScript, porque los números son dobles. La solución es llevar los enteros grandes como cadenas. Unas reglas más que se olvidan: sin ceros a la izquierda (007 es inválido), sin + inicial, sin punto decimal final (1. es inválido), y NaN e Infinity no son JSON válido — serialízalos como null o una cadena.
Cadenas, Unicode y codificación
Las cadenas deben usar comillas dobles, y los caracteres de control de U+0000 a U+001F deben escaparse. La barra puede escaparse opcionalmente como \/, por eso algunos codificadores emiten <\/script> — una forma legal de no romper una etiqueta script de HTML. La RFC 8259 obliga a UTF-8 para el JSON intercambiado entre sistemas.
Los caracteres fuera del Plano Multilingüe Básico (BMP), como la mayoría de los emoji, se escriben como un par sustituto (surrogate) de escapes \u y no como uno solo. Los sustitutos solitarios y sin pareja son técnicamente inválidos, pero algunos parsers los aceptan — una trampa de portabilidad que solo aflora cuando tus datos cruzan a una implementación más estricta.
Cosas que parecen JSON pero no lo son
Los errores más comunes vienen de tratar JSON como JavaScript. Las comas finales son inválidas. Los comentarios no existen en JSON — JSON5 y JSONC los añaden, pero un parser estricto de RFC 8259 los rechazará. Las cadenas con comillas simples y las claves de objeto sin comillas también son inválidas, por familiares que parezcan.
Más sutil es la marca de orden de bytes (BOM). La RFC 8259 dice que los productores NO DEBEN (MUST NOT) añadir una BOM y los consumidores PUEDEN (MAY) ignorarla, pero la BOM no es parte de JSON, así que una BOM UTF-8 al inicio de un archivo puede hacer fallar a un parser estricto en el primer byte. El espacio en blanco insignificante se limita a espacio, tabulador, salto de línea y retorno de carro — nada más.
Conclusiones
Rechaza las claves duplicadas donde una decisión de seguridad o corrección dependa del valor.
Lleva los enteros de 64 bits como cadenas para que sobrevivan a parsers de doble precisión como el de JavaScript.
No dependas del orden de claves de objeto — la especificación define los objetos como no ordenados, aunque la mayoría de parsers conserven el orden de inserción.
Recuerda que cualquier valor es JSON de nivel superior válido bajo la RFC 8259, no solo objetos y arrays.
Si quieres comentarios o comas finales, quieres JSON5/JSONC — convierte antes de que un parser estricto vea los datos. El formateador JSON de este sitio valida contra la gramática estricta de la RFC 8259, así que estos problemas afloran de inmediato.