checked_json 0.1.0
checked_json: ^0.1.0 copied to clipboard
A JSON object type you only get by checking a value, with typed readers that name the field that is absent or the wrong shape.
checked_json #
A JSON object you only get by checking a value. Holding a JsonObject means
the value was looked at and found to be a JSON object, so nothing downstream
checks it again. Its fields are read through typed readers that say which
field was wrong and what it should have been.
import 'package:checked_json/checked_json.dart';
final user = JsonObject.decode('{"name": "Ada", "tags": ["maths"]}');
user.string('name'); // 'Ada'
user.strings('tags'); // ['maths']
user.integerOrNull('born'); // null: absent
user.integer('name'); // throws JsonFieldException: `name` is not an integer
The doors in #
The map inside a JsonObject is private, so code outside the library cannot
wrap an unchecked value in one. A value becomes one through a door that checks
it:
JsonObject.decode(text)for wire text. AFormatExceptionwhen the text is not JSON, or is JSON of another kind.JsonObject.parse(value)for a value that is already decoded. Null when it is not a JSON object.object(k)andobjects(k)for an object nested in another.JsonObject.of(map)for an object you build yourself, for atoJson, from a map whose static type is already string-keyed.
The readers #
string, integer, number, boolean, object, list, strings and
objects. A plain reader requires its field and throws a
JsonFieldException naming the field and the shape it wanted. Its OrNull
twin takes an absent or null field as null, and still refuses one of the wrong
type. A default for an absent field is the caller's ??, so the default sits
where it is used. has(k) tells a field present with a null value apart from
an absent one, and raw(k) gives a field as it was decoded.
JsonFieldException extends FormatException: a bad field is a condition
you're meant to catch, not a programming bug. Code that already catches
FormatException still catches it.
What it guarantees, and what it doesn't yet #
as JsonObjectandis JsonObjectdo not check. An extension type is erased at runtime, sox as JsonObjectisx as Map<String, Object?>and fails with aTypeErrorwhere a door would have thrown aFormatException. UseJsonObject.parseinstead, and the same goes for aJsonObjectpattern.- For now a
JsonObjectis also aMap<String, Object?>. It implements the map type, soobj['k']still compiles, reads a field without a check, and aJsonObjectgoes wherever a map is wanted. 0.2.0 removes this, leaving the readers as the only way to a field. parsematches the map's runtime type.jsonDecodealways makes a string-keyed map, so its output is fine. AMap<dynamic, dynamic>, as YAML and Flutter platform channels deliver one, gives null even when every key is a string: copy it withMap<String, Object?>.fromfirst.- Whole numbers are exact only below 2^53 in magnitude.
integerreads3or3.0(as some writers spell one, and as a web build reads every whole number) but never3.5. A double is taken only when its size is strictly below 2^53, where it stands for one whole number; 2^53 itself is refused, because9007199254740993.0decodes to it too. - Nested values are not deep-checked up front. A door checks that the value is an object; each field is checked when its reader reads it.
Licence #
Apache-2.0. Copyright 2026 Enspyr Pty Ltd.