Hero image

Json Serialisation in Flutter

Mar 01, 2024
Flutter

In this article, we’re going to talk about serialising and deserialing an object to/from JSON in Flutter/Dart.

JSON serialisation in Dart uses the dart:convert package for basic conversion functions and the json_serializable package to generate serialisation and deserialisation helper functions.

Check out a complete example on GitHub: minibuildsio/flutter_json_serialisation_example.

Dependencies

We need to add the following regular and dev dependencies. json_annotation provides the annotations that json_serializable looks for and uses to generate the serialisation helper functions. build_runner is the standard Dart package for code generation.

dependencies:
  json_annotation: ^4.8.1

dev_dependencies:
  json_serializable: ^6.7.1
  build_runner: ^2.4.8

Find the latest versions: json_annotation, json_serializable, build_runner.

Using the JsonSerializable annotation

In the example below we have created WeatherData a class with a couple of fields of different types. The class has been annotated with @JsonSerializable() which json_serializable searches for and generates

The part directive, part 'model.g.dart', tells build_runner where to put the generated code.

import 'package:json_annotation/json_annotation.dart';

part 'model.g.dart'

enum WeatherType {
  sunny, rainy
}

@JsonSerializable()
class WeatherData {
  final DateTime date;
  final double temperature;
  final WeatherType weatherType;

  WeatherData(this.date, this.temperature, this.weatherType);
}

Generating helper functions

With the class annotated we can now use build_runner to generate the helper functions using the command below:

dart run build_runner build

This will generate two functions in the model.g.dart file _$WeatherDataFromJson and _$WeatherDataToJson. These functions convert from a Map<String, dynamic> to a String and vice versa. The dart:convert package provided the functions jsonDecode and jsonEncode to convert objects to maps and vice versa.

We can put all this together in a factory function fromJson and function toJson.

factory WeatherData.fromJson(String json) => _$WeatherDataFromJson(jsonDecode(json));
String toJson() => jsonEncode(_$WeatherDataToJson(this));

The complete class

The complete class with the fromJson and toJson functions looks like this:

import 'dart:convert';
import 'package:json_annotation/json_annotation.dart';

part 'model.g.dart';

enum WeatherType {
  sunny, rainy
}

@JsonSerializable()
class WeatherData {
  final DateTime date;
  final double temperature;
  final WeatherType weatherType;

  WeatherData(this.date, this.temperature, this.weatherType);

  factory WeatherData.fromJson(String json) => _$WeatherDataFromJson(jsonDecode(json));
  String toJson() => jsonEncode(_$WeatherDataToJson(this));
}

Using the toJson and fromJson functions

With those functions defined, you can use them like so:

final weatherDataString = WeatherData(
  DateTime(2024, 3, 1, 12, 0, 0), 15.6, WeatherType.sunny
).toJson();

final weatherData = WeatherData.fromJson(
  '{"date": "2024-02-29T12:00:00", "temperature": 12.4, "weatherType": "rainy"}'
);

Configuration and customisation

Often you’ll need to handle field names that are snake_case for example instead of camelCase. Annotations can be used to customise the serialisation, for example, the @JsonKey can be used to rename a field.

@JsonKey(name: 'weather_type')
final WeatherType weatherType;

Note you will need to re-run the code generation, dart run build_runner build, after any changes to the class.