What this tool does
A JSON sample becomes Dart classes, each with a fromJson factory and a toJson method.
{ "id": 1, "firstName": "Ada", "address": { "city": "Paris" } }
class Root {
final int id;
final String firstName;
final Address address;
Root({required this.id, required this.firstName, required this.address});
factory Root.fromJson(Map<String, dynamic> json) => Root(
id: json['id'] as int,
firstName: json['firstName'] as String,
address: Address.fromJson(json['address'] as Map<String, dynamic>),
);
Map<String, dynamic> toJson() => <String, dynamic>{
'id': id,
'firstName': firstName,
'address': address.toJson(),
};
}
No build_runner, no annotations, no generated part file: the mapping is right there, and you can change it.
The key never leaves
Dart field names cannot hold a dash or start with a digit, and class is reserved. When a name has to change, both directions keep the key:
final String contentType;
final int class_;
factory Root.fromJson(Map<String, dynamic> json) => Root(
contentType: json['content-type'] as String,
class_: json['class'] as int,
);
Map<String, dynamic> toJson() => <String, dynamic>{
'content-type': contentType,
'class': class_,
};
Because the mapping is code rather than a convention, nothing is guessed at runtime — and you can read what will be sent before you send it.
Lists and nested objects
A list of objects becomes a class of its own, and the mapping walks it:
items: (json['items'] as List<dynamic>)
.map((e) => ItemsItem.fromJson(e as Map<String, dynamic>))
.toList(),
A list of scalars uses cast, which is cheaper: (json['tags'] as List<dynamic>).cast<String>().
What a sample cannot say
Every field is final and required, and none is nullable — because the document had a value for each. That makes a missing key a TypeError at decode time, naming the field, rather than a null that travels three screens before it breaks.
Only a null gives dynamic, which accepts anything and checks nothing. An empty or mixed list gives List<dynamic> for the same reason. Those are the three places worth revisiting once you have a second payload.
Private by design
Everything runs locally in your browser with JavaScript. Your data is never uploaded, which makes the tool safe for sensitive content, and it keeps working offline.