Since AL programming is avaible it is pretty easy to work with json.
AL supports us with JsonObject, JsonArray, JsonValue and JsonToken, which can be one of the other three types.

Let us check some code examples, how you can consume and work with JSON data.
We receiving following JSON array and need to import it into customer table:

[
	{
		no: "00001",
		name: "Dummy Customer 1"
	},
	{
		no: "00002",
		name: "Dummy Customer 2"
	}
]

The AL code would look like this:

procedure ImportCustomerJsonArray(CustomerJsonArray: JsonArray)
var
    CustomerJsonObject: JsonObject;
    JsonTokenHelper: JsonToken;
begin
    foreach JsonTokenHelper in CustomerJsonArray do begin
        CustomerJsonObject := JsonTokenHelper.AsObject();
        ImportCustomerJson(CustomerJsonObject);
    end;
end;

procedure ImportCustomerJson(CustomerJsonObject: JsonObject)
var
    Customer: Record Customer;
    JsonTokenHelper: JsonToken;
    No: Code[20];
begin
    CustomerJsonObject.Get('no', JsonTokenHelper);
    No := JsonTokenHelper.AsValue().AsText();
    if not Customer.Get(No) then begin
        Customer.Init();
        Customer."No." := No;
        Customer.Insert(true);
    end;
    CustomerJsonObject.Get('name', JsonTokenHelper);
    Customer.Name := JsonTokenHelper.AsValue().AsText();
    // ... 
    Customer.Modify(true);
end;

As you can see, not that hard!
But what happens if we have a more nested JSON?

{
    no: "00001",
    name: "Dummy Customer 1",
    address: {
        street: "Dummy Street 1",
        zipcode: "12345",
        city: "Berlin"
    }
}

Do you know the power of “selectToken“? You can use JPath there (if you dont know what it is: here)

// ...
CustomerJsonObject.SelectToken('$.adress.street', JsonTokenHelper);
Customer.Address := JsonTokenHelper.AsValue().AsText();
// ...

Let us be a little bit more complicated:

{
    no: "00001",
    name: "Dummy Customer 1",
    address: [
        {   
            type: "BILLING"
            street: "Dummy Street 1",
            zipcode: "12345",
            city: "Berlin"
        },
        {   
            type: "SHIPPING"
            street: "Dummy Street 1",
            zipcode: "99999",
            city: "SomewhereElse"
        }
    ]
}

And the AL code:

// ...
CustomerJsonObject.SelectToken('$.adress[?(@.type==''BILLING'')].street', JsonTokenHelper);
Customer.Address := JsonTokenHelper.AsValue().AsText();
// ...

Still easy! You just need to understand how JPath works.

It`s time to make the code a bit more clean

In all cases we fill our “JsonTokenHelper” and after get the value as text. Lets create a function for it.

procedure GetValueAsText(JPath: Text; JToken: JsonToken) ReturnValue: Text
var
    SelectToken: JsonToken;
begin
    JToken.SelectToken(JPath, SelectToken);
    ReturnValue := SelectToken.AsValue().AsText();
end;

And here how we can use it:

procedure ImportCustomerJson(CustomerJsonObject: JsonObject)
var
    Customer: Record Customer;
    JsonTokenHelper: JsonToken;
    No: Code[20];
begin
    No := GetValueAsText('$.no', CustomerJsonObject.AsToken());
    if not Customer.Get(No) then begin
        Customer.Init();
        Customer."No." := No;
        Customer.Insert(true);
    end;
    Customer.Name := GetValueAsText('$.name', CustomerJsonObject.AsToken());
    Customer.Address := GetValueAsText('$.adress[?(@.type==''BILLING'')].street', CustomerJsonObject.AsToken());
    Customer.Modify(true);
end;

Our code looks much cleaner now.

Let me provide you a “JSON Helper” codeunit.


codeunit 50000 "JSON Helper"
{
    procedure GetValueAsText(Path: Text; JToken: JsonToken) ReturnValue: Text
    var
        SelectToken: JsonToken;
    begin
        if JToken.SelectToken(Path, SelectToken) then
            if not SelectToken.AsValue().IsNull() then
                ReturnValue := SelectToken.AsValue().AsText().Replace('\"', '"');
    end;

    procedure GetValueAsBoolean(Path: Text; JToken: JsonToken) ReturnValue: Boolean
    var
        SelectToken: JsonToken;
    begin
        if JToken.SelectToken(Path, SelectToken) then
            if not SelectToken.AsValue().IsNull() then
                ReturnValue := SelectToken.AsValue().AsBoolean()
    end;

    procedure GetValueAsInt(Path: Text; JToken: JsonToken) ReturnValue: Integer
    var
        SelectToken: JsonToken;
    begin
        if JToken.SelectToken(Path, SelectToken) then
            if not SelectToken.AsValue().IsNull() then
                ReturnValue := SelectToken.AsValue().AsInteger()
    end;

    // ...
}

>> see complete code here <<

This codeunit contains functions for different datatypes, it takes care of escaping, NULL values and broken JSON values.

Is it helpfull? Is something unclear?