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.

1
  • You are mixing 2 different libraries to process JSON - SuperObject and System.JSON. Pick one as a good start. Commented Aug 24, 2020 at 13:19

1 Answer 1

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.
Sign up to request clarification or add additional context in comments.

2 Comments

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 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.