json_query 0.1.0
json_query: ^0.1.0 copied to clipboard
Extract and map fields from deeply nested JSON into Dart models without manual traversal.
json_query #
Extract and map fields from deeply nested JSON into Dart models without writing repetitive manual traversal code.
final response = {
'status': true,
'data': {
'user': {
'id': 123,
'profile': {'name': 'Ebrahim', 'avatar': '...'},
'subscription': {
'package': {'name': 'Fiber', 'speed': 100},
},
},
},
};
final user = JsonQuery(response).map<User>(
{
'id': '.data.user.id',
'name': '.data.user.profile.name',
'package': '.data.user.subscription.package.name',
},
User.fromJson,
);
No matter how deep or awkwardly-shaped the API response is, you say what
fields you want and what to do with them — json_query handles the
traversal.
Basic extraction #
final id = JsonQuery(json).get('.data.user.id');
A missing field returns null instead of throwing:
JsonQuery(json).get('.data.user.nickname'); // null, no exception
Pass required: true when a missing value should be a hard error instead:
JsonQuery(json).get('.data.user.id', required: true); // throws JsonQueryAccessException if absent
Renaming fields into a flat map #
JsonQuery(json).pick({
'id': '.data.user.user_id',
'name': '.data.user.full_name',
});
Lists #
final names = JsonQuery(json).pickList(
'.data.users',
{'id': '.id', 'name': '.profile.name'},
);
Or apply a wildcard inline to project a field out of every element:
JsonQuery(json).get('.data.users[].id'); // [1, 2, 3]
Mapping straight to a Dart object #
Works with a manual fromJson, json_serializable, or Freezed — anything
shaped like T Function(Map<String, dynamic>):
final user = JsonQuery(json).map<User>(
{'id': '.data.user.id', 'name': '.data.user.name'},
User.fromJson,
);
final users = JsonQuery(json).mapList<User>(
'.data.users',
{'id': '.id', 'name': '.name'},
User.fromJson,
);
Compiled queries #
If you run the same projection against many payloads (e.g. once per item in a paginated list), compile it once to skip re-parsing the paths:
final query = JsonQuery.compile({
'id': '.data.user.id',
'name': '.data.user.profile.name',
});
final user = query.map<User>(json, User.fromJson);
Query syntax #
.field,.a.b.c— dot field access[n]— array index[]— apply the rest of the path to every element of a list
That's the whole language. json_query is a JSON projection and mapping
tool for application developers, not a general-purpose JSON query language —
there is deliberately no filtering syntax, scripting, or arithmetic. See the
architecture notes for what's intentionally left out and why.
Error handling #
JsonQuerySyntaxException— the path string itself is malformed.JsonQueryAccessException— only thrown whenrequired: trueand the path can't be resolved (wrong type along the way, missing field, out-of-range index).
By default, unresolvable paths simply evaluate to null.
Performance #
- Operates directly on already-decoded
Map/List/dynamic— never touchesdart:convertitself. - A path string is parsed once into a
Listof segments, which is the compiled query — there's no separate AST or compiler stage. JsonQuery.compile()lets you parse a projection once and reuse it across many payloads.
See test/benchmark/bench_traversal.dart for a manual sanity comparison
against plain Map traversal.
HTTP client integration #
json_query has zero HTTP dependency by design. Since Dio, package:http,
and Chopper responses are already decoded Map/List values, no
integration package is required to use json_query with any of them —
JsonQuery(response.data) works as-is.