json_typed 0.0.1 copy "json_typed: ^0.0.1" to clipboard
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 #

CI

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.
  • OrNull variants that return null instead 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:

  • jsonDecodeObject returns a JsonObject and throws a JsonTypeError for a document of another kind.
  • jsonDecodeArray returns a JsonArray and throws a JsonTypeError for a document of another kind.
  • jsonDecodeValue returns a JsonValue for a document of any kind, including a bare string, number, bool or null.

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 JsonKeyError for everything a JsonObject getter can throw,
  • catch JsonTypeError for every type mismatch, wherever it happens,
  • catch FormatException for 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

0
likes
160
points
63
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Typed access to decoded JSON without wrapper objects. Extension types over dart:convert maps, lists and values, with typed getters.

Repository (GitHub)
View/report issues

Topics

#json

License

MIT (license)

More

Packages that depend on json_typed