Hi folks,
In this article I will share all the code that I have been used to fetch User information from JsonPlaceholder Rest API and stored the JSON response in D365 Business Central tables.
Let's see the result first:
For this demo I have created the 5 objects and organized in structure like below screenshot:
Note: Not including 50102_UserCard.Page.al in this article.
You can check the response from the JsonPlaceholder API from URL: https://jsonplaceholder.typicode.com/users
So what I am going to do here to fetch and store this User information that I am getting from the above URL, I will first create a table object that will store all information that available in code and value pair.
As the API contains following response:
Based on the API Response, Let's create a TABLE
------------------------
table 50100 JP_Users
{
Caption = 'Json Placeholder Users';
DataClassification = ToBeClassified;
fields
{
field(1; UUID; Integer)
{
DataClassification = ToBeClassified;
AutoIncrement = true;
}
field(2; id; Integer) { DataClassification = ToBeClassified; }
field(3; name; Text[50]){ DataClassification = ToBeClassified; }
field(4; username; Text[30]){ DataClassification = ToBeClassified; }
field(5; email; Text[30]){ DataClassification = ToBeClassified; }
field(6; street; Text[50]){ DataClassification = ToBeClassified; }
field(7; suite; Text[50]){ DataClassification = ToBeClassified; }
field(8; city; Text[50]){ DataClassification = ToBeClassified; }
field(9; zipcode; Text[50]){ DataClassification = ToBeClassified; }
field(10; lat; Text[250]){ DataClassification = ToBeClassified; }
field(11; lng; Text[250]){ DataClassification = ToBeClassified; }
field(12; phone; Text[30])
{
DataClassification = ToBeClassified;
ExtendedDatatype = PhoneNo;
}
field(13; website; Text[150])
{
DataClassification = ToBeClassified;
ExtendedDatatype = URL;
}
field(14; companyName; Text[100]){ DataClassification = ToBeClassified; }
field(15; companyCatchPhrase; Text[250]){ DataClassification = ToBeClassified; }
field(16; companyBS; Text[250]){ DataClassification = ToBeClassified; }
}
keys
{
key(PK; UUID)
{
Clustered = true;
}
}
}
Create 3 different codeunits:
50146 JSON_Methods
50100 API_RequestHandlerCodeunit
50101 API_ResponseHandlerCodeunit
Codeunit 1: I will use this codeunit for to read values from JSON Object
---------------------
codeunit 50146 JSON_Methods
{
trigger OnRun()
begin
end;
// GetJsonValue is use to get the value format and helpful to convert in any data type
procedure GetJsonValue(var json_Object: JsonObject; Property: Text; var json_Value: JsonValue): Boolean
var
json_Token: JsonToken;
begin
if not json_Object.Get(Property, json_Token) then
exit;
json_Value := json_Token.AsValue();
exit(true);
end;
// Work for Text Response
procedure GetJsonValueAsText(var json_Object: JsonObject; Property: Text) Value: Text
var
json_Value: JsonValue;
begin
if not GetJsonValue(json_Object, Property, json_Value) then
exit;
Value := json_Value.AsText;
end;
procedure GetJsonValueAsBoolean(var json_Object: JsonObject; Property: Text) Value: Boolean
var
json_Value: JsonValue;
begin
if not GetJsonValue(json_Object, Property, json_Value) then
exit;
Value := json_Value.AsBoolean();
end;
procedure GetJsonValueAsInteger(var json_Object: JsonObject; Property: Text) Value: Integer
var
json_Value: JsonValue;
begin
if not GetJsonValue(json_Object, Property, json_Value) then
exit;
Value := json_Value.AsInteger();
end;
procedure GetJsonValueAsDecimal(var json_Object: JsonObject; Property: Text) Value: Decimal
var
json_Value: JsonValue;
begin
if not GetJsonValue(json_Object, Property, json_Value) then
exit;
Value := json_Value.AsDecimal();
end;
procedure GetJsonToken(json_Object: JsonObject; tokenKey: Text) json_Token: JsonToken;
begin
if not json_Object.Get(tokenKey, json_Token) then
Error('Token not found with key %1', tokenKey);
end;
procedure SelectJsonToken(json_object: JsonObject; path: Text) json_Token: JsonToken;
begin
if not json_object.SelectToken(path, json_Token) then
Error('Token not found with path %1', path);
end;
}
Codeunit 2: I will use this codeunit for making request
-----------------------
codeunit 50100 API_RequestHandlerCodeunit
{
trigger OnRun()
begin
end;
procedure GetResponse(requestURL: Text; erroMsg: Text): Text
var
httpClient: HttpClient;
httpResponseMsg: HttpResponseMessage;
httpRequestMsg: HttpRequestMessage;
response: Text;
recWebServiceLog: Record WebServiceLog;
cuCommon: Codeunit CommonCodeunit;
begin
erroMsg := '';
cuCommon.InsertWebServiceLog('', '', requestURL, recWebServiceLog);
if not httpClient.Get(requestURL, httpResponseMsg) then begin
erroMsg := 'The call to webservice is failed';
end;
if not httpResponseMsg.IsSuccessStatusCode then begin
erroMsg += '\The request call returned an error message. \Detail: \Status Code: ' +
Format(httpResponseMsg.HttpStatusCode) + '\Description: ' + httpResponseMsg.ReasonPhrase;
end;
httpResponseMsg.Content.ReadAs(response);
cuCommon.UpdateWebServiceLog(recWebServiceLog);
exit(response);
end;
}
Codeunit 3: I will use this code unit for handling response
-------------------------
codeunit 50101 API_ResponseHandlerCodeunit
{
trigger OnRun()
begin
end;
procedure UsersInfoFromResponse(response: Text): Boolean
var
responseArray: JsonArray;
json_Token: JsonToken;
json_Object: JsonObject;
userInfo_JsonObject: JsonObject;
i: Integer;
begin
//if json_Object.ReadFrom(response) then begin
if json_Token.ReadFrom(response) then begin
if json_Token.IsArray then // json_Token.IsArray; json_Token.IsObject; json_Token.IsValue;
responseArray := json_Token.AsArray();
for i := 0 to responseArray.Count() - 1 do begin
// Get First Array Result
responseArray.Get(i, json_Token);
// Convert JsonToken to JsonObject
if json_Token.IsObject then begin
userInfo_JsonObject := json_Token.AsObject();
insertUsersDetail(userInfo_JsonObject);
end;
end;
end;
//end;
exit(true);
end;
procedure insertUsersDetail(userInfoJsonObject: JsonObject)
var
recJPUser: Record JP_Users;
json_Methods: Codeunit JSON_Methods;
retJsonValue: JsonValue; // this can be used when getting value from GetJsonValue method
addressJsonObject: JsonObject;
addressJsonToken: JsonToken;
geoJsonObject: JsonObject;
geoJsonToken: JsonToken;
companyJsonObject: JsonObject;
companyJsonToken: JsonToken;
begin
recJPUser.Reset();
recJPUser.Init();
recJPUser.id := json_Methods.GetJsonToken(userInfoJsonObject, 'id').AsValue().AsInteger();
recJPUser.id := json_Methods.GetJsonValueAsInteger(userInfoJsonObject, 'id');
if json_Methods.GetJsonValue(userInfoJsonObject, 'id', retJsonValue) then
recJPUser.id := retJsonValue.AsInteger();
recJPUser.name := json_Methods.GetJsonValueAsText(userInfoJsonObject, 'name');
// With GetJsonValue
if json_Methods.GetJsonValue(userInfoJsonObject, 'username', retJsonValue) then
recJPUser.username := retJsonValue.AsText();
recJPUser.email := json_Methods.GetJsonValueAsText(userInfoJsonObject, 'email');
// Using separate function GetJsonValueAsText
// Start: Get Address Details
if userInfoJsonObject.Get('address', addressJsonToken) then begin
if addressJsonToken.IsObject then begin
addressJsonObject := addressJsonToken.AsObject();
recJPUser.street := json_Methods.GetJsonValueAsText(addressJsonObject, 'street');
recJPUser.suite := json_Methods.GetJsonValueAsText(addressJsonObject, 'suite');
recJPUser.city := json_Methods.GetJsonValueAsText(addressJsonObject, 'city');
recJPUser.zipcode := json_Methods.GetJsonValueAsText(addressJsonObject, 'zipcode');
// Start: Geo
if addressJsonObject.Get('geo', geoJsonToken) then begin
if geoJsonToken.IsObject then begin
geoJsonObject := geoJsonToken.AsObject();
recJPUser.lat := json_Methods.GetJsonValueAsText(geoJsonObject, 'lat');
recJPUser.lng := json_Methods.GetJsonValueAsText(geoJsonObject, 'lng');
end;
end;
// Stop: Geo
end;
end;
// Stop: Get Address Details
recJPUser.phone := json_Methods.GetJsonValueAsText(userInfoJsonObject, 'phone');
recJPUser.website := json_Methods.GetJsonValueAsText(userInfoJsonObject, 'website');
// Start: Company Details
if userInfoJsonObject.Get('company', companyJsonToken) then begin
if companyJsonToken.IsObject then begin
companyJsonObject := companyJsonToken.AsObject();
recJPUser.companyName := json_Methods.GetJsonValueAsText(companyJsonObject, 'name');
recJPUser.companyCatchPhrase := json_Methods.GetJsonValueAsText(companyJsonObject,
'catchPhrase');
recJPUser.companyBS := json_Methods.GetJsonValueAsText(companyJsonObject, 'bs');
end;
end;
// Stop: Company Details
recJPUser.Insert();
end;
}
Finally Create a list page with Action "Get Users From API":
-----------------------
page 50100 JP_Users
{
Caption = 'Json Placeholder Users';
PageType = List;
ApplicationArea = All;
UsageCategory = Lists;
SourceTable = JP_Users;
CardPageId = "JP User Card";
layout
{
area(Content)
{
repeater(GroupName)
{
field(UUID; UUID)
{
ApplicationArea = All;
}
field(id; id) { ApplicationArea = All; }
field(name; name) { ApplicationArea = All; }
field(username; username) { ApplicationArea = All; }
field(email; email) { ApplicationArea = All; }
field(street; street) { ApplicationArea = All; }
field(suite; suite) { ApplicationArea = All; }
field(city; city) { ApplicationArea = All; }
field(zipcode; zipcode) { ApplicationArea = All; }
field(lat; lat) { ApplicationArea = All; }
field(lng; lng) { ApplicationArea = All; }
field(phone; phone) { ApplicationArea = All; }
field(website; website) { ApplicationArea = All; }
field(companyName; companyName) { ApplicationArea = All; }
field(companyCatchPhrase; companyCatchPhrase) { ApplicationArea = All; }
field(companyBS; companyBS) { ApplicationArea = All; }
}
}
}
actions
{
area(Processing)
{
action(GetUsersFromAPI)
{
ApplicationArea = All;
Caption = 'Get Users From API';
trigger OnAction();
var
apiCodeunit: Codeunit API_RequestHandlerCodeunit;
response: Text;
errorMsg: Text;
apiResponseHandler: Codeunit API_ResponseHandlerCodeunit;
begin
response := apiCodeunit.GetResponse('https://jsonplaceholder.typicode.com/users', errorMsg);
if errorMsg <> '' then
Error(errorMsg)
else
Message('Your API Call Response: \' + response);
if response <> '' then begin
if apiResponseHandler.UsersInfoFromResponse(response) then
Message('Records inserted Successfully!');
end;
end;
}
}
}
}
That's All, Happy Coding!
Stay Tuned!