Working with JSON in Dart

 

The most interesting data returned from an HTTP request to a RICOH THETA camera is a JSON string.

Although it is a very simple concept, it is easy to lose track of what is a Dart string and what is a Dart map. It is also tricky to print out the JSON string with nice indentation that is friendly to people.

Get Response Body from Camera

Using the http Dart package, the response is a Dart object.

String url = 'http://192.168.1.1/osc/info';
http.Response response = await http.get(url);
print(response.runtimeType);
// output
// Response

At this point, the response is nice and pleasant to work with. We can use a dot notation to access properties.

print(response.body);
// output is below
{"manufacturer":"RICOH","model":"RICOH THETA SC2","serialNumber":"20001005","firmwareVersion":"01.51","supportUrl":"https://theta360.com/en/support/","gps":false,"gyro":true,"endpoints":{"httpPort":80,"httpUpdatesPort":80},"apiLevel":[2],"api":["/osc/info","/osc/state","/osc/checkForUpdates","/osc/commands/execute","/osc/commands/status"],"uptime":1795,"_wlanMacAddress":"58:38:79:2b:ad:c5","_bluetoothMacAddress":"6c:21:a2:47:d9:05"}

Oh no, the response is one giant line of text without pretty indents. In my VS Code editor, it looks like this:

JSON output

Sadness.

Format Response Body

I want output on my terminal to look like formatted text with nice indents.

JSON formatted

Happiness.

Until yesterday, I was using the function below to format the output.

import 'dart:convert';

void prettyPrint(String input) {
  const JsonDecoder decoder = JsonDecoder();
  const JsonEncoder encoder = JsonEncoder.withIndent('  ');
  final dynamic object = decoder.convert(input);
  final dynamic prettyString = encoder.convert(object);
  prettyString.split('\n').forEach((dynamic element) => print(element));
}

Instead of using a separate function, I’ve started to print the output like this:

  Map responseBody = jsonDecode(response.body);
  print(JsonEncoder.withIndent('  ').convert(responseBody));

Decode the JSON String

In the previous example, my objective was to get formatted JSON output from the camera in my console.

The first step is to get the JSON string into a Dart map.

At this point, if I print out the contents of the map, I will see format that looks like JSON without the double quotes.

  print(responseBody);

dart map

It is easy to forget that that object is a Dart Map and not a JSON String.

Although a Dart map is much more useful in a Dart program than a JSON string, I’ve sadly lost the type definition in the value portion of the map. The value is of type dynamic.

print(responseBody.runtimeType);
...
// output
// _InternalLinkedHashMap<String, dynamic>

Access Camera Properties

The happy part is that I can access any of the values in the Dart map such as firmware version.

  Map responseBody = jsonDecode(response.body);
  // print single value from map
  print("firmware: ${responseBody['firmwareVersion']}");
  // output
  // firmware: 01.51

It’s now easy to assign variables to the data from the camera. I can adjust my application to the specific camera model API.

  Map responseBody = jsonDecode(response.body);
  // print single values from map
  String firmware = responseBody['firmwareVersion'];
  String cameraModel = responseBody['model'];
  String serialNumber = responseBody['serialNumber'];
  print('Your camera is a $cameraModel running firmware $firmware');
  print('The camera serial number is $serialNumber');

The output of the code is:

Your camera is a RICOH THETA SC2 running firmware 01.51
The camera serial number is 20001005

Reference