Simplifying JSON Conversion To Model

Ali Ammar
3 min readJun 27, 2023

Many applications require retrieving data from an API, often in the form of JSON, with some responses containing lists of objects. After receiving the data as a string, you need to convert it to its real data structure using jsonDecode, which is either a Map or a List (if you’re using Dio, you don’t need to use jsonDecode).

You might want to convert it into a Dart class using json_serializable or other tools like a website or VS Code plugin, or write it manually,In the end, you’ll have a class with a fromJson constructor/method/static function that takes a Map and converts it into the Dart class. Here’s an example:

@JsonSerializable()
class User {
final String id;
User(this.id);

factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}

You can use this class with Dio or http as shown below:

Future<User> getUserHttp() async {
final res = await http.get(Uri.parse('profile'));
return User.fromJson((jsonDecode(res.body) as Map).cast());
}

Future<User> getUserDio() async {
final res = await Dio().get<Map>("profile");
return User.fromJson(res.data!.cast());
}

If you have an array of objects instead of a single value, you can use it like this:

Future<List<User>> getUsersHttp() async {
final res = await http.get(Uri.parse('profile'));
return (jsonDecode(res.body) as List)
.map((e) => User.fromJson((e as Map).cast()))
.toList();
}

Future<List<User>> getUsersDio() async {
final res = await Dio().get<List>("friends");
return res.data!.map((e) => User.fromJson((e as Map).cast())).toList();
}

In this article, we will extract the shared logic to ease the code and reuse it in all our API requests without repetition. We’ll create a separate function that takes the fromJson function and the received data, performing the necessary logic for us:


// used with http for convert a single value
T convertStringToModel<T>(
T Function(Map<String, dynamic> map) fromJson, String response) {
return fromJson((jsonDecode(response) as Map).cast());
}

// used with http for conver a List of value
List<T> convertStringListToModel<T>(
T Function(Map<String, dynamic> map) fromJson, String response) {
return (jsonDecode(response) as List)
.map((e) => fromJson((e as Map).cast()))
.toList();
}
// used with dio for convert a single value
T convertMapToModel<T>(
T Function(Map<String, dynamic> map) fromJson, Map response) {
return fromJson((response).cast());
}

// used with dio for convert a List of value
List<T> convertListToModel<T>(
T Function(Map<String, dynamic> map) fromJson, List data) {
return data.map((e) => fromJson((e as Map).cast())).toList();
}

These functions use generic types, allowing them to convert any class. Here are examples of how to use them:

Future<User> getUserHttp2() async {
final res = await http.get(Uri.parse('profile'));
return convertStringToModel(User.fromJson, res.body);
}

Future<List<User>> getUsersHttp2() async {
final res = await http.get(Uri.parse('profile'));
return convertStringListToModel(User.fromJson, res.body);
}

Future<User> getUserDio2() async {
final res = await Dio().get<Map>("profile");
return convertMapToModel(User.fromJson, res.data!);
}

Future<List<User>> getUsersDio2() async {
final res = await Dio().get<List>("friends");
return convertListToModel(User.fromJson, res.data!);
}

By extracting this shared logic into separate functions, you can simplify your code and reuse it across multiple API requests, avoiding repetition.

Conclusion:

In this article, we explored the process of converting JSON data into Dart model, specifically focusing on scenarios where the data received is in the form of JSON lists. We discussed how to use the jsonDecode function to convert JSON strings into their corresponding Dart data structures, such as Maps or Lists.

To simplify the conversion process and eliminate repetitive code, we introduced a set of functions that abstract the conversion logic. These functions, convertStringToModel, convertStringListToModel, convertMapToModel, and convertListToModel, take a fromJson function and the received data as input, automatically performing the necessary conversions.

By utilizing these generic conversion functions, you can streamline the code for handling API responses in your Dart applications. The functions enable you to convert JSON strings or lists to specific Dart classes without duplicating conversion code across multiple API requests.

With this approach, you can enhance code reusability, improve maintainability, and reduce the potential for errors when dealing with JSON data in Dart applications.

--

--

Ali Ammar

Flutter and Nodejs Developer from iraq, working at Creative Advanced Technologies