I've built a delphi client sample in Delphi XE5 that utilises the Rest library:
All served by an ASP.net Web API that generates a dataset based on dynamic queries from Delphi. I can successfully run the queries and return data to the client and render the data, however boolean fields are rendered blank.
EDIT Surprisingly, Embarcadero's TRestResponseDatasetAdapter does this internally to create fields:
procedure TCustomJSONDataSetAdapter.CB_CollectFieldDefs(const AJSONObject: TJSONObject);
var
LJSONPair: TJSONPair;
begin
for LJSONPair in AJSONObject do
begin
DoAddDataSetFieldDef(LJSONPair.JsonString.Value, ftString);
end;
end;
The field types are all hardcoded to ftString!
This is the returned json:
"Table": [
{
"Id": 34,
"Node": "Navision_ASN_1",
"FormatId": 2,
"Value": null,
"ParentID": null,
"DocumentOrder": 1,
"Combined": false,
"Delimiter": "",
"ValueType": 0,
"Ignore": false,
"IsIndexer": false,
"IsCounter": false,
"StringFormat": null
},
{
"Id": 35,
"Node": "MessageHeader",
"FormatId": 2,
"Value": null,
"ParentID": 34,
"DocumentOrder": 2,
"Combined": false,
"Delimiter": "",
"ValueType": 0,
"Ignore": false,
"IsIndexer": false,
"IsCounter": false,
"StringFormat": null
},
{
"Id": 52,
"Node": "Consignment",
"FormatId": 2,
"Value": null,
"ParentID": 34,
"DocumentOrder": 13,
"Combined": false,
"Delimiter": "",
"ValueType": 0,
"Ignore": false,
"IsIndexer": false,
"IsCounter": false,
"StringFormat": null
},
{
"Id": 53,
"Node": "Line",
"FormatId": 2,
"Value": null,
"ParentID": 52,
"DocumentOrder": 18,
"Combined": false,
"Delimiter": "",
"ValueType": 0,
"Ignore": false,
"IsIndexer": false,
"IsCounter": false,
"StringFormat": null
}
]
You can't!
The issue comes down to the TJsonObject class from Embarcadero Delphi. In the Rest.Response.Adapter unit the json returned is parsed into a TJsonObject, and then all the TJsonPairs in the object are iterated over in CB_CollectFieldDefs and CB_CollectFieldData.
First problem: CB_CollectionFieldDefs hardcodes ftString as the data type to add to the dataSet for each field definition. So I returned the field types from my Web API call to remove the guesswork and built the field definitions manually. When the RestResponseDataSetAdapter has field definitions, the unit correctly skips CB_CollectionFieldDefs, this leads to the second problem.
Second problem: the TjsonPair in the object does not correctly parse boolean json values. By the time CB_CollectFieldData is called, all the boolean values which should be variant types are empty strings. So we get the exception 'Could not convert variant of type (UnicodeString) into type (Boolean)'.
I have sadly had to drop this promising set of components in favour of enhancing Fabricio Colombo's excellent rest client api. Using the pattern in his GetAsDataSet logic, I created a number of post methods to post json (since the json creation from built in delphi units were incorrect, I substituted with SuperObject). I introduced PostJson and CreateDataset which both return TClientDataSets.
function TResource.CreateDataset(data: string; table: string = ''; titles: string = ''): TClientDataSet;
var
vJson: ISuperObject;
begin
vJson := SuperObject.SO(data);
Result := TJsonToDataSetConverter.CreateDataSetMetadata(vJson, table, titles);
TJsonToDataSetConverter.ToDataSet(Result, vJson.O[table]);
end;
// which allows me to do:
ds := jsonrestclient1.Resource(url)
.ContentType(RestUtils.MediaType_Json)
.Accept(restutils.MediaType_Json)
.PostJson(json, 'Table', 'Titles');
// or
rs := jsonrestclient1.Resource(url)
.ContentType(RestUtils.MediaType_Json)
.Accept(restutils.MediaType_Json);
data:= rs.PostJson(Query) ;
vJson := SO(data);
fHasMore := vJson.B['HasMore'];
ds:= rs.CreateDataset(data, 'Table', 'Titles');