2

I am calling a 3rd Party API using Indy

var loRespJson: TMemoryStream;
IdHTTP1.GET(lsURL, loRespJson)

and it returns a JSON array:

[
    {
        "Active": "1",
        "SourceId": "215",
        "SourceName": "MyVal1"
    },
    {
        "Active": "1",
        "SourceId": "383",
        "SourceName": "MyVal2"
    }
]

In turn my function creates a new JSON object, adds additional info plus the response, and return it to the calling program. Desired result:

{
    "responseCode":"200",
    "companyNo":"0268895",
    "responseMessage": [
        {
            "Active": "1",
            "SourceId": "215",
            "SourceName": "MyVal1"
        },
        {
            "Active": "1",
            "SourceId": "383",
            "SourceName": "MyVal2"
        }
    ]
}

How can I achieve the above? If I add using the following, it creates "" (quotes) around the array which is a big problem when parsing the JSON:

loJSon.AddPair(TJSONPair.Create('responseCode', IntToStr(idHttp1.ResponseCode)));
loJSon.AddPair(TJSONPair.Create('companyNo', CompanyNo));

if idHttp1.ResponseCode = 200 then
begin
  lsRespMsg := StreamToString(loRespJSon);
  liSuper := SO(lsRespMsg);
  loJSon.AddPair(TJSONPair.Create('responseMessage', liSuper.AsJSon()));
  …

I have also tried looping through the JSON aray but that option adds "" around each array item

{ create an json-array }
loJSA := TJsonArray.Create();
{ add array to object }
loJSP := TJSONPair.Create('responseMessage', loJSA);
loJSon.AddPair(loJSP);

if liSuper.IsType(stArray) then
begin
  for i := 0 to liSuper.AsArray.Length - 1 do
  begin
    loSubscription := liSuper.AsArray[i];
    loJSA.Add(loSubscription.AsJSon());
  end;
end;

Any help will be greatly appreciated! Thanks.

Peter Wolf
  • 3,700
  • 1
  • 15
  • 30
Johan
  • 317
  • 3
  • 11
  • You are mixing 2 different libraries to process JSON - [SuperObject](https://github.com/hgourvest/superobject) and [System.JSON](http://docwiki.embarcadero.com/Libraries/en/System.JSON). Pick one as a good start. – Peter Wolf Aug 24 '20 at 13:19

1 Answers1

5

It seems that you used loJSon: TJSONObject from unit System.JSON in your attempt to build JSON new response. Then you parsed response body received from TIdHTTP using function SO() from SuperObject library, which is not very compatible with System.JSON.

The approach was good so far, but you should stick to a single library. After parsing the response you added a pair the TJSONObject with value liSuper.AsJSon() which was a string. And that explains the double quotes enclosing the array.

The proper solution using just System.JSON could look like this:

uses
  System.SysUtils, System.JSON;

const
  ResponseMessageStr = '[{"Active":"1","SourceId":"215","SourceName":"MyVal1"},{"Active":"1","SourceId":"383","SourceName":"MyVal2"}]';
var
  ResponseJSON: TJSONObject;
begin
  ResponseJSON := TJSONObject.Create;
  try
    ResponseJSON.AddPair('responseCode', '200');
    ResponseJSON.AddPair('companyNo', '0268895');
    ResponseJSON.AddPair('responseMessage', TJSONObject.ParseJSONValue(ResponseMessageStr));
    Writeln(ResponseJSON.Format());
  finally
    ResponseJSON.Free;
  end;
end.

In the above snippet I used TJSONObject.ParseJSONValue to parse response message and append it to the resulting JSON object. Although my response message is stored in a string constant, you can easily adapt the solution to be used with TMemoryStream or TIdHTTP. Check out all invariants of TJSONObject.ParseJSONValue.

The snippet produces output:

{
    "responseCode": "200",
    "companyNo": "0268895",
    "responseMessage": [
        {
            "Active": "1",
            "SourceId": "215",
            "SourceName": "MyVal1"
        },
        {
            "Active": "1",
            "SourceId": "383",
            "SourceName": "MyVal2"
        }
    ]
}

Also note that TJSONObject.AddPair has multiple invariants for your convenience. Another point is that I used Format method to pretty-print the content of JSON object, but you should probably use ToJSON in production.

Solution using SuperObject library that produces equivalent result:

uses
  System.SysUtils, SuperObject;

const
  ResponseMessageStr = '[{"Active":"1","SourceId":"215","SourceName":"MyVal1"},{"Active":"1","SourceId":"383","SourceName":"MyVal2"}]';
var
  ResponseJSON: ISuperObject;
begin
  ResponseJSON := TSuperObject.Create;
  ResponseJSON.I['responseCode'] := 200;
  ResponseJSON.S['responseCode'] := '0268895';
  ResponseJSON.O['responseMessage'] := SO(ResponseMessageStr);
  Writeln(ResponseJSON.AsJSon(True));
  Readln;
end.
Peter Wolf
  • 3,700
  • 1
  • 15
  • 30
  • 1
    thanks for pointing me in the right direction. My project is in Delphi 2010 so I couldn't use the example. However, standardizing to iSuperObject helped a lot and the fix was as simple as loResult.O['responseMessage'] := SO(lsRespMsg); – Johan Aug 24 '20 at 14:39
  • 1
    @Johan I have added snippet to perform the same task using SuperObject. Next time remember to put all the constraints in your question. We can't see where `TJSONPair` or `TJSONArray` come from. – Peter Wolf Aug 24 '20 at 15:09