Lección 18 · 18 de 20
JSON con fromJson y toJson · Dart
Lea y escriba JSON en Dart con jsonDecode y jsonEncode, y conviértalo en objetos con tipos mediante fromJson y toJson, como en Flutter.

`dart:convert` trae lo necesario para trabajar con JSON. `jsonDecode` convierte el texto en estructuras de Dart: los objetos JSON pasan a Map<String, dynamic>, las listas a List, y los números, textos, booleanos y null a sus tipos. body es lo que podría responder una API: una lista con dos clientes (dos cadenas seguidas en el código se unen en una sola).
Trabajar con mapas por toda la aplicación es frágil, así que se convierten en objetos con tipo. El factory `Customer.fromJson` lee cada clave y la convierte a su tipo con as: as String? acepta el null de Pablo, y List<String>.from(json['tags'] ?? const []) convierte la lista dinámica en una lista de textos, o usa una vacía si la clave falta. Si el JSON trae un tipo inesperado, falla aquí, en un solo sitio, y no en mitad de la interfaz.
`toJson` hace el camino inverso: devuelve un mapa con tipos básicos. No hace falta llamarlo: `jsonEncode` llama por su cuenta a toJson() de cualquier objeto que no sepa convertir, y por eso jsonEncode(customers.first) funciona directamente.
Si el texto no es JSON válido (aquí, una coma sobrante), jsonDecode lanza FormatException. Esta pareja fromJson/toJson es la convención que siguen los modelos de cualquier aplicación Flutter; paquetes como json_serializable solo escriben este mismo código por usted.
Código · main.dart
import 'dart:convert';class Customer { final int id; final String name; final String? email; final List<String> tags; Customer({required this.id, required this.name, this.email, this.tags = const []}); // JSON arrives as Map<String, dynamic>: read each key with its type. factory Customer.fromJson(Map<String, dynamic> json) => Customer( id: json['id'] as int, name: json['name'] as String, email: json['email'] as String?, tags: List<String>.from(json['tags'] ?? const []), ); Map<String, dynamic> toJson() => {'id': id, 'name': name, 'email': email, 'tags': tags};}const body = '[{"id": 17, "name": "Carmen Ruiz", "email": "carmen@example.com",' ' "tags": ["vip"]}, {"id": 18, "name": "Pablo Gil", "email": null}]';void main() { final list = jsonDecode(body) as List; // text -> Dart lists and maps final customers = [for (final item in list) Customer.fromJson(item)]; for (final c in customers) { print('#${c.id} ${c.name} <${c.email ?? 'no email'}> ${c.tags}'); } print(jsonEncode(customers.first)); // jsonEncode calls toJson() for you try { jsonDecode('{"id": 19,}'); } on FormatException catch (e) { print('Bad JSON: ${e.message}'); }}Salida · dart run main.dart
#17 Carmen Ruiz <carmen@example.com> [vip]
#18 Pablo Gil <no email> []
{"id":17,"name":"Carmen Ruiz","email":"carmen@example.com","tags":["vip"]}
Bad JSON: Unexpected characterPara recordar
jsonDecodeconvierte texto JSON en mapas y listas de Dart.fromJsonconvierte el mapa en un objeto con tipos.toJsondevuelve un mapa, yjsonEncodelo usa automáticamente.- Use
as Tipo?para los campos que pueden sernull. - Un JSON mal formado lanza
FormatException.
Ejercicio
Añada a Customer un campo bool active que en el JSON se llame is_active y valga true si falta, e inclúyalo en cada línea de la salida y en toJson.