Lewis Cianci I'm a passionate mobile-first developer, and I've been making apps with Flutter since it first released. I also use ASP.NET 5 for web. Given the chance, I'll talk to you for far too long about why I love Flutter so much.

How to parse JSON strings in Flutter

7 min read 2069

If you were to interact with an API, what format do you think the response would be in? It would probably — or almost definitely — be in JSON.

JSON is the standard for transferring typed data from one point to another point. If you query an API, or even want to save settings in your app, you’re going to have to use JSON sooner or later.

In this article, we’ll take a look at how to parse a JSON string in Flutter. We’ll review:

Serialization and deserialization in JSON

When dealing with JSON, there are two main actions that can occur:

  • Serialization — Converting a data object from its native language type to a JSON string
  • Deserialization — Converting from a JSON string to a native object

Actually, this is something we can do right now, in the very same browser that you’re using to read this article. If you hit F12 on your keyboard and head over to the developer console, you can type in the following:

JSON.stringify({serialization: 'fun'})

The result of this is: '{"serialization":"fun"}'.

Okay, so what just happened? We created an in-memory JavaScript object, and then immediately converted that object to JSON via JSON.stringify. We can see it’s a string, because it is surrounded by quotes.

We can run this process in reverse by running the following:

JSON.parse('{"serialization":"fun"}')

The result of this is as follows:

Converting Between A Json String And A Javascript Object With JSON.parse



Now, we’re converting the string representation of this object back to a bona-fide JavaScript object. As JavaScript is an untyped language, we don’t need to specify the type to which we would like to serialize or deserialize our JSON string.

In a typed language, like C#, serializing and deserializing from objects to strings and vice versa is similar. However, one difference is that when we deserialize, we’re required to specify what type we would like to deserialize to by using the following:

JsonConvert.DeserializeObject<T>

In the command above, T is the destination type to which we are trying to deserialize.

Perhaps you’d assume that something as simple and ubiquitous as serializing data in Flutter would be as easy as accomplishing the same thing in C# or JavaScript. Unfortunately, that’s not the case, but there’s good reason for this challenge.

Why parsing JSON in Flutter is a challenge

The key difference between serializing and deserializing JSON strings in Flutter and other languages is that Flutter doesn’t support a runtime feature known as “reflection.” With reflection, other languages are able to inspect objects for information that helps with object serialization.

However, Flutter’s lack of reflection is actually a good thing. Without reflection, Flutter code avoids the associated performance caveats and results in a smaller installable binary for the end user.

We can still easily parse JSON strings in Flutter, but we need to do more than just specify a type. Fortunately, we can generate all of the code that we need to accomplish this, so we don’t have to write it by hand.


More great articles from LogRocket:


There are two situations you can be in when you want to serialize data within Flutter.

In one situation, you are in control of the data classes yourself, and you would like to convert your data to or from JSON to send to an API or to store on a device.

In the other situation, you’re not in control of the data classes yourself, and are receiving JSON from an API. You would like to convert this JSON to strongly-typed data you can operate on within your Flutter app.

We’ll consider both situations in this article. First, we’ll look at how to serialize a class within an app when we are in control of our data. Then, we’ll review deserializing JSON data in Flutter from a remote source.

Serializing a class with JSON in a Flutter app

Let’s imagine that we have a music app within which users can set songs as their favorite. For that to work, we would need a class called Favorite. Within the class, we’d typically have properties such as the song’s title and artist.

The end result would be something like this:

class Favorite {
  final String title;
  final String artist;

  Favorite(this.title, this.artist);
}

So how do we serialize and deserialize a class like this in Flutter? You could either do it yourself or automatically generate the JSON handling code. Let’s take a look at both options.

Defining your own toJson and fromJson methods

If you only have a few classes that you want to serialize or deserialize, it’s an option to simply do it yourself. This means defining your own toJson and fromJson methods that are responsible for converting data from a Map<String, dynamic> back to the original data model.

If we did this, our class would look like this:

class Favorite {
  final String title;
  final String artist;

  Favorite(this.title, this.artist);

  /// Convert from JSON response stream to Favorite object
  Favorite.fromJson(Map<String, dynamic> json)
      : title = json['title'],
        artist = json['artist'];

  /// Convert an in-memory representation of a Favorite object to a Map<String, dynamic>
  Map<String, dynamic> toJson() => {
        'title': title,
        'artist': artist,
      };
}

We can then use jsonEncode or jsonDecode with our fromJson and toJson methods, respectively. But there are some downsides to defining your own methods for converting JSON data in Flutter.

For example, if we ever updated the class members, we would have to manually update the properties. It’s also possible for us to refer to the wrong member, or just make a typo and try to map a non-existent property accidentally.

This method also adds a lot of overhead for working with JSON within our Flutter apps. Using existing packages to generate JSON serialization and deserialization code can be more convenient.

Automatically generating your JSON handling code

The official Flutter documentation says that you can write your own JSON mapping code by hand for smaller applications. In reality, you’re always better off generating the JSON serialization and deserialization code.

The packages that automatically generate JSON handling code are well tested and have been around for as long as Flutter has, so you know they work.

One of these packages is json_serializable. Using some easy attributes within our Flutter code, we can have our code generated for JSON serialization in no time.

First, add json_serializable to your pubspec.yaml file as a dependency and also as a dev_dependency. We also need to add a reference to build_runner, as json_serializable uses build_runner to create the functionality for us.

Next, annotate our class with @JsonSerializable. This instructs the json_serializable package to generate the code we require to serialize this class to and from JSON in Flutter.

We also want to add the part directive to the top of this file, and specify favorite.g.dart. When we initially write this, we’ll get red squiggles underneath, as the file has not been created yet. But we need to define this in our file in order for the json_serializable package to work.

part 'favorite.g.dart'

@JsonSerializable
class Favorite {
  final String title;
  final String artist;

  Favorite(this.title, this.artist);
}

With these changes, now we can run the following command in our terminal:

flutter pub run build_runner build

And after some console output, we’ll be able to see our favorites.g.dart file appear within our project. The contents of that file are as follows:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'favorite.dart';

// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************

Favorite _$FavoriteFromJson(Map<String, dynamic> json) => Favorite(
      json['title'] as String,
      json['artist'] as String,
    );

Map<String, dynamic> _$FavoriteToJson(Favorite instance) => <String, dynamic>{
      'title': instance.title,
      'artist': instance.artist,
    };

Unfortunately, json_serializable doesn’t expose these toJson or fromJson functions directly from within the generated code. That means it’s up to us to include them in our original file. All in all, our final favorite.dart file should look like this:

import 'package:json_annotation/json_annotation.dart';

part 'favorite.g.dart';

@JsonSerializable()
class Favorite {
  final String title;
  final String artist;

  Favorite(this.title, this.artist);

  factory Favorite.fromJson(Map<String, dynamic> json) => _$FavoriteFromJson(json);

  Map<String, dynamic> toJson() => _$FavoriteToJson(this);
}

When we want to serialize or encode the Favorite object, we use the following command:

final favoriteJson = jsonEncode(Favorite('one', 'two'));

If we wanted to convert this text-based JSON back to an original object, we can do the following:

final favorite = Favorite.fromJson(jsonDecode(favoriteJson));

That’s how we manage our JSON when we are in control of the objects within our own app. But what do we do when we aren’t in control of the data classes? If, for example, we are querying a remote API for which we don’t have the data structure?

Deserializing JSON data in Flutter from a remote source

If we have a remote API, we can use an online tool to convert from the JSON supplied to classes we can use within our app, complete with toJson and fromJSON methods. One such tool that we’ll be using to demonstrate this is a JSON to Dart converter available on Github.

For this sample, we’ll use the Bored API, which can randomly give us a task to do if we feel bored. The Bored API responds in JSON, and is a good fit for this purpose. Since it’s random, the task you receive will be different from the example we’re using below.

In my case, the response I received from the API was the following:

{"activity":"Go for a walk","type":"relaxation","participants":1,"price":0,"link":"","key":"4286250","accessibility":0.1}

To serialize and parse this JSON data within our Flutter app, simply paste it into the JSON to Dart converter, as shown below:

Json To Dart Converter With Json Data Pasted In And Generated BoredAPI Code

Now we can just copy and paste the BoredAPI class into our app as we see fit. In this case, our generated code for the Bored API would look like this:

class BoredAPI {
  String? activity;
  String? type;
  int? participants;
  int? price;
  String? link;
  String? key;
  double? accessibility;

  BoredAPI(
      {this.activity,
      this.type,
      this.participants,
      this.price,
      this.link,
      this.key,
      this.accessibility});

  BoredAPI.fromJson(Map<String, dynamic> json) {
    activity = json['activity'];
    type = json['type'];
    participants = json['participants'];
    price = json['price'];
    link = json['link'];
    key = json['key'];
    accessibility = json['accessibility'];
  }

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = new Map<String, dynamic>();
    data['activity'] = this.activity;
    data['type'] = this.type;
    data['participants'] = this.participants;
    data['price'] = this.price;
    data['link'] = this.link;
    data['key'] = this.key;
    data['accessibility'] = this.accessibility;
    return data;
  }
}

As we can see, we have all our class members. We have the fromJson and toJson functions declared as well. Also, our generated code supports null-safety, so we can use it in more recent versions of Flutter.

With those in hand, we can now safely interact with this API and encode and decode JSON data in Flutter as we need to.

Conclusion

Parsing JSON strings in Flutter is a little bit more difficult than it is in other languages. As we’ve seen, this is due to the lack of reflection within Flutter at runtime.

However, in my opinion, Flutter more than makes up for these minor annoyances by letting us generate the applicable classes to serialize our JSON as needed.

We’ve also seen how we can create functionality for converting to and from JSON, even when we don’t own the data that is coming into our app, by generating JSON classes for responses received from APIs.

If you’re interacting with an API and serializing to and from JSON is getting you down, you could also consider using something like OpenAPI or Swagger to generate all your API code for you. That way, you’ll be able to deal with just the API functionality instead of manually converting your objects to and from JSON.

Enjoy the serialization journey!

: Full visibility into your web and mobile apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page web and mobile apps.

.
Lewis Cianci I'm a passionate mobile-first developer, and I've been making apps with Flutter since it first released. I also use ASP.NET 5 for web. Given the chance, I'll talk to you for far too long about why I love Flutter so much.

Leave a Reply