3.4 JSON¶
JSON (JavaScript Object Notation) es un formato de texto para guardar e intercambiar datos. Es el formato más usado entre aplicaciones y servidores web, porque es compacto, fácil de leer para una persona y todos los lenguajes saben procesarlo.
{
"usuarios": [
{"id": 1, "nombre": "Juan", "edad": 30},
{"id": 2, "nombre": "Ana", "edad": 25}
]
}
Qué contiene un JSON¶
| En JSON | Ejemplo | En Dart es... |
|---|---|---|
Objeto { } |
{"id": 1} |
un mapa (o un objeto de una clase) |
Array [ ] |
[1, 2, 3] |
una lista |
| Texto | "Ana" |
una cadena |
| Número | 25 · 3.5 |
un entero o decimal |
| Booleano | true · false |
un booleano |
| Nulo | null |
el valor nulo |
Las reglas son estrictas: las claves y los textos van siempre entre comillas dobles, no se admite una coma al final de una lista ni de un objeto y no hay comentarios. La mayoría de errores con JSON son una de estas tres cosas.
Dart incluye la librería dart:convert: jsonDecode(texto) convierte el texto en mapas y listas, y jsonEncode(datos) hace lo contrario. Para escribir el resultado con sangría se usa JsonEncoder.withIndent(' '). Los valores llegan como dynamic, así que a menudo hay que indicar el tipo (as Map<String, dynamic>).
Leer, modificar y escribir¶
import 'dart:convert';
void mostrar(Map<String, dynamic> datos) {
for (final u in datos['usuarios']) {
print('ID: ${u['id']}, Nombre: ${u['nombre']}, Edad: ${u['edad']}');
}
}
void main() {
const texto =
'{"usuarios": [{"id": 1, "nombre": "Juan", "edad": 30}, {"id": 2, "nombre": "Ana", "edad": 25}]}';
final datos = jsonDecode(texto) as Map<String, dynamic>;
mostrar(datos);
final usuarios = datos['usuarios'] as List;
usuarios[1]['edad'] = 26; // actualizar
usuarios.add({'id': 3, 'nombre': 'Eva', 'edad': 22}); // insertar
usuarios.removeWhere((u) => u['id'] == 1); // eliminar
print('--- después de los cambios ---');
mostrar(datos);
print(JsonEncoder.withIndent(' ').convert(datos));
}
Salida:
ID: 1, Nombre: Juan, Edad: 30
ID: 2, Nombre: Ana, Edad: 25
--- después de los cambios ---
ID: 2, Nombre: Ana, Edad: 26
ID: 3, Nombre: Eva, Edad: 22
{
"usuarios": [
{
"id": 2,
"nombre": "Ana",
"edad": 26
},
{
"id": 3,
"nombre": "Eva",
"edad": 22
}
]
}
El proceso siempre es el mismo en tres pasos:
- Convertir el texto en estructuras del lenguaje (mapas, listas u objetos).
- Trabajar con ellas como con cualquier mapa o lista. Se actualiza un valor asignándolo (
usuarios[1]['edad'] = 26), se inserta conaddy se elimina conremoveWhere, como con cualquier lista o mapa. - Convertirlas de nuevo en texto, con sangría si lo van a leer personas.
Trabajar con archivos y controlar los errores¶
Los datos suelen estar en un archivo. Al leerlo pueden pasar dos cosas que hay que controlar siempre: que el archivo no exista o que su contenido no sea un JSON válido. Un JSON mal formado lanza una FormatException.
import 'dart:convert';
import 'dart:io';
List<dynamic>? cargar(String ruta) {
final archivo = File(ruta);
if (!archivo.existsSync()) {
print("No existe el archivo '$ruta'");
return null;
}
try {
final datos = jsonDecode(archivo.readAsStringSync());
return datos['usuarios'] as List<dynamic>;
} on FormatException {
print("El archivo '$ruta' no contiene un JSON válido");
return null;
}
}
void main() {
cargar('no_existe.json');
File('malo.json').writeAsStringSync('{ esto no es json');
cargar('malo.json');
final datos = {
'usuarios': [
{'id': 1, 'nombre': 'Juan', 'edad': 30},
{'id': 2, 'nombre': 'Ana', 'edad': 25},
],
};
File('bueno.json').writeAsStringSync(jsonEncode(datos));
final usuarios = cargar('bueno.json');
print('Cargados ${usuarios?.length} usuarios');
File('malo.json').deleteSync();
File('bueno.json').deleteSync();
}
Salida:
No existe el archivo 'no_existe.json'
El archivo 'malo.json' no contiene un JSON válido
Cargados 2 usuarios
Comprobar la existencia antes de abrir y capturar el error de formato permite dar un mensaje claro en vez de que el programa se detenga. Los archivos de texto se guardan en UTF-8, la codificación habitual del JSON.
Errores frecuentes¶
| Error | Cómo evitarlo |
|---|---|
| Comillas simples en el texto del JSON | En JSON solo valen las dobles |
| Una coma de más al final | Quítala: JSON no la permite |
| Esperar un número y recibir texto (o al revés) | Comprueba el tipo o convierte |
| Pedir una clave que no existe | Comprueba con las consultas seguras del apartado 3.2 |
| Perder las tildes al guardar | Usa UTF-8 en lectura y escritura |
Para practicar¶
Haz el ejercicio 3.4 de JSON, la gestión de usuarios en un archivo.