json_typed 0.0.1
json_typed: ^0.0.1 copied to clipboard
Typed access to decoded JSON without wrapper objects. Extension types over dart:convert maps, lists and values, with typed getters.
json_typed #
Typed access to decoded JSON in Dart, without wrapper objects.
JsonObject, JsonArray and JsonValue are extension types over the maps, lists and values that dart:convert produces. Wrapping costs nothing at runtime. Every read returns the requested type or throws.
Features #
- Decoders for a top-level object, array or any value.
- Typed getters for strings, bools, ints, doubles, nested objects and arrays.
OrNullvariants that returnnullinstead of throwing.- Fallbacks for missing keys and JSON nulls that keep the type check.
- Errors that name the key, the rejected value and the expected type.
Getting started #
Requires Dart 3.3 or later.
dart pub add json_typed
Usage #
import 'package:json_typed/json_typed.dart';
final user = jsonDecodeObject('''
{
"name": "Ann",
"age": 30,
"active": true,
"nickname": null,
"address": {"city": "Helsinki"},
"tags": ["admin", "beta"]
}
''');
final name = user.getString('name'); // 'Ann'
final age = user.getInt('age'); // 30
final score = user.getDouble('age'); // 30.0, an int converts to a double
final nickname = user.getStringOrNull('nickname'); // null
final role = user.getString('role', or: 'member'); // 'member'
final city = user.getObject('address').getString('city'); // 'Helsinki'
final tags = user.getArray('tags').asStrings; // ['admin', 'beta']
for (final tag in user.getArray('tags')) {
print(tag.asString);
}
Top-level values #
A JSON document holds one top-level value. Pick the decode function for the kind you expect:
jsonDecodeObjectreturns aJsonObjectand throws aJsonTypeErrorfor a document of another kind.jsonDecodeArrayreturns aJsonArrayand throws aJsonTypeErrorfor a document of another kind.jsonDecodeValuereturns aJsonValuefor a document of any kind, including a bare string, number, bool ornull.
All three throw a FormatException for malformed JSON.
final ids = jsonDecodeArray('[1, 2, 3]').asInts; // [1, 2, 3]
final count = jsonDecodeValue('42').asInt; // 42
Numbers #
JSON has one number type. asDouble and getDouble accept any number. asInt and getInt accept a number without a fraction, so 1, 1.0 and 1e2 all read as ints on every platform, and 1.5 throws. On the web, numbers are JavaScript numbers: integers above 2^53 lose precision.
Missing keys and nulls #
The typed getters treat a missing key and a JSON null the same way. containsKey tells them apart. getValue returns a JSON null as a value, and isNull reports it, as it does for a value in an array, in entries or at the top level.
| Call | Result |
|---|---|
user.getString('role') |
throws JsonKeyNotFoundError |
user.getStringOrNull('role') |
null |
user.containsKey('nickname') |
true |
user.containsKey('role') |
false |
user.getValue('nickname').isNull |
true |
Fallbacks #
or covers absence only. A missing key and a JSON null return the fallback, and a value of another kind still throws. getStringOrNull(key) ?? fallback reads the same but also returns the fallback for a value of another kind.
| Call | Result |
|---|---|
user.getString('role', or: 'member') |
'member' |
user.getString('age', or: 'member') |
throws JsonKeyTypeError |
user.getStringOrNull('age') ?? 'member' |
'member' |
Use or when a wrong type is a bug you want to see. Use an OrNull getter when a wrong type should count as absent.
Error handling #
Every error the package throws itself is a JsonTypeError, a JsonKeyError or both. Malformed input throws a FormatException from dart:convert. Array access outside the array throws the same errors as a List.
| Error | Thrown by |
|---|---|
FormatException |
the decode functions, on malformed JSON |
JsonTypeError<T> |
as* getters and the object and array decoders |
JsonKeyNotFoundError |
JsonObject getters without a fallback, on missing key or null |
JsonKeyTypeError<T> |
JsonObject getters, on a value of another kind |
RangeError |
JsonArray index operator, on an index outside the array |
StateError |
Iterable members such as first or single, on an empty array |
A value of mismatching type throws, even when a fallback is given.
try {
user.getInt('name');
} on JsonKeyTypeError catch (error) {
print(error); // JsonKeyTypeError: Value "Ann" for key "name" is not of type int
}
JsonKeyTypeError is both a JsonTypeError and a JsonKeyError, so:
- catch
JsonKeyErrorfor everything aJsonObjectgetter can throw, - catch
JsonTypeErrorfor every type mismatch, wherever it happens, - catch
FormatExceptionfor malformed input.
For arrays, dart:core already has the OrNull forms: elementAtOrNull, firstOrNull, lastOrNull and singleOrNull return null instead of throwing.
The Json* errors, RangeError and StateError extend Error: they mean the input broke the shape the code expects. Use a fallback for a field that may be absent, an OrNull getter when a wrong type should also count as absent, and catch the errors at the boundary where you can report or recover.
License #
MIT