ESP32: JSON Merge Patch

Introduction

In this tutorial we are going to check how to use the Nlohmann/json library to apply the JSON merge patch operation to an object. We will be using the ESP32 and the Arduino core.

The JSON merge patch operation (RFC here) allows to describe a set of modifications to be applied to a source JSON object [1]. These modifications are described using a syntax that closely mimics the source object being modified [1], being represented as a JSON object themselves.

If the provided merge patch object contains properties that do not appear in the source object, those properties are added [1]. If the source object contains the properties, the values are replaced [1]. In the particular case of the source object containing the property but the merge patch object having it as a Null value, this indicates that the property should be removed [1].

It’s important to take in consideration that the merge patch operation is different from the patch operation (the RFC is different, as can be seen here). We already covered the patch operation here.

Note that all the code we are covering on this tutorial can be used in general C++ programs.

The tests shown in the sections below were performed on a ESP32-E FireBeetle board from DFRobot. The Arduino core version used was 2.0.0 and the Arduino IDE version was 1.8.15, working on Windows 8.1. The version of the Nlohmann/json library used was 3.10.2.

The JSON merge patch code

We will start by library includes. For our example, we will only need the json.hpp lib.

#include <json.hpp>

We will write the rest of the code in the Arduino setup function. As usual, the first thing we take care of will be opening a serial connection, so later we can print the results of our program.

Serial.begin(115200);

Then we will define a string containing a JSON object. This object, for illustration purposes, will contain possible attributes of a person data structure.

  • Name: a string containing the name of the person.
  • Age: an integer with the age of the person.
  • Confidential: a string to contain some possible confidential information.
  • Address: an object containing two properties, namely a code and a street.
char personStr[] = R"(
 {
   "name": "John",
   "age": 10,
   "confidential": "something",
   "address": {
     "street": "St. Street",
     "code": "1234-12"
   }
 }
)";

Next we will define the merge patch object. For illustration purposes, we will do the following operations:

  • Changing the “name” property to the value “Jeff“. To achieve this, our object will need to contain the property “name” (like the original), but with the new value.
  • Removing the property “confidential“. To do so, our object will need to have the same “confidential” property, but with a value of null.
  • Removing the nested property “street“. We need to have the parent object property “address“, with the nested “street” property inside with the value null.
  • Changing the nested property “code” to a new value. Once again, we need to have the “address” property and inside the “code” property with the new value.
  • Adding a new “avenue” property to the “address“. To do so, we simply need to add this new property inside the “address” object.

To better illustrate the previous operations, the final merge patch object, stored in a string, is shown below:

char mergePatchStr[] = R"(
 {
   "name": "Jeff",
   "confidential": null,
   "address": {
     "street": null,
     "code": "1234-12",
     "avenue": "new avenue"
   }
 }
)";

Now we parse both the original object and the merge patch object. We do so with a call to the parse static method, which returns a json object with the parsed result.

nlohmann::json person = nlohmann::json::parse(personStr);
nlohmann::json mergePatch = nlohmann::json::parse(mergePatchStr);

To apply the merge patch, we simply need to call the merge_patch method on the json object containing the original JSON, and pass as input the json object that contains the merge patch to be applied.

Note that this method returns void, meaning it will mutate the original json object.

person.merge_patch(mergePatch);

To finalize, we will take care of serializing the result to a string and printing it to the serial port.

std::string patchedSerializedObject = person.dump(3);
Serial.println(patchedSerializedObject.c_str());

The whole code is available in the snippet below.

#include <json.hpp>

void setup() {

  Serial.begin(115200);

  char personStr[] = R"(
   {
     "name": "John",
     "age": 10,
     "confidential": "something",
     "address": {
       "street": "St. Street",
       "code": "1234-12"
     }
   }
  )";

  char mergePatchStr[] = R"(
   {
     "name": "Jeff",
     "confidential": null,
     "address": {
       "street": null,
       "code": "1234-12",
       "avenue": "new avenue"
     }
   }
  )";

  nlohmann::json person = nlohmann::json::parse(personStr);
  nlohmann::json mergePatch = nlohmann::json::parse(mergePatchStr);

  person.merge_patch(mergePatch);

  std::string patchedSerializedObject = person.dump(3);
  Serial.println(patchedSerializedObject.c_str());
}

void loop() {}

Testing the code

As usual, to test the code, simply compile it and upload it to your device. When the procedure is finished, open the Arduino IDE serial monitor.

You should get a result like the one illustrated in figure 1. As can be seen, the final object we obtained has the changes we have defined in our merge patch object.

Result of the JSON merge patch operation on the ESP32.
Figure 1 – Result of the JSON merge patch operation on the ESP32.

Suggested ESP32 Readings

References

[1] https://datatracker.ietf.org/doc/html/rfc7386

Leave a Reply