1

I've seen some examples here and there on how to POST data to a server using Indy, but my question is how can I view the answer the server provides?

Here is what I have, from the user Bruce McGee, and modified myself a bit:

function ExecuteAPI: string;
var
  lHTTP: TIdHTTP;
  lParamList: TStringList;
begin
  lParamList := TStringList.Create;
  lParamList.Add('<input type=text name=StoreName value="Hálitopuro Produtos">');
  lParamList.Add('<input type=text name=StoreID value="123456"> ');
  lParamList.Add('<input type=text name=Username value="Admin"> ');
  lParamList.Add('<input type=password name=Password value="Password123">');
  lParamList.Add('<input type=text name=method value="ReportView">');
  lParamList.Add('<input type=text name=ObjectID value="425">');
  lParamList.Add('<input type=text name=Par1 value="Category name">');
  lParamList.Add('<input type=text name=Par2 value="Ref/Name/Descr"> ');
  lParamList.Add('<input type=text name=Par3 value="false"> ');
  lParamList.Add('<input type=text name=Par4 value="false"> ');

  lHTTP := TIdHTTP.Create(nil);

  try
    Result := lHTTP.Post('https://www.rumo.com.br/sistema/adm/APILogon.asp', lParamList);
  finally
    lHTTP.Free;
    lParamList.Free;
  end;
end;

The API states that the server also returns a XML, regardless on what the request or result is, but how can I view it? For example, by filling a TMemo?

Community
  • 1
  • 1

2 Answers2

7

I've seen some examples here and there on how to POST data to a server using Indy

You are not populating the TStringList correctly. DO NOT store the actual HTML tags in it, just their name=value pairs by themselves, eg:

lParamList.Add('StoreName=Hálitopuro Produtos');
lParamList.Add('StoreID=123456');
lParamList.Add('Username=Admin');
lParamList.Add('Password=Password123');
lParamList.Add('method=ReportView');
lParamList.Add('ObjectID=425');
lParamList.Add('Par1=Category name');
lParamList.Add('Par2=Ref/Name/Descr');
lParamList.Add('Par3=false');
lParamList.Add('Par4=false');

how can I view the answer the server provides?

TIdHTTP.Post() returns the server's response to you. There are two overloaded versions of Post() for this purpose - one that returns the response as a String, and one that fills a TStream with the raw response bytes. You are calling the first one, so just use the String however you want, eg:

var
  XML: string;
begin
  XML := ExecuteAPI;
  // use XML as needed, for example:
  // Memo1.Text := XML;
end;

However, that being said...

The API states that the server also returns a XML, regardless on what the request or result is

XML is not textual data, it is binary data with textual elements in it. Treating the XML as binary is important for proper charset handling for non-ASCII characters. You should use the TStream version of Post() and then load the raw data to an actual XML parser for further processing (as I'm sure you will eventually want to actually do something based on the content of the response, not just look at it), eg:

procedure ExecuteAPI(Response: TStream);
var
  lHTTP: TIdHTTP;
  lParamList: TStringList;
begin
  lParamList := TStringList.Create;
  try
    lParamList.Add('StoreName=Hálitopuro Produtos');
    lParamList.Add('StoreID=123456');
    lParamList.Add('Username=...');
    lParamList.Add('Password=...');
    lParamList.Add('method=ReportView');
    lParamList.Add('ObjectID=425');
    lParamList.Add('Par1=Category name');
    lParamList.Add('Par2=Ref/Name/Descr');
    lParamList.Add('Par3=false');
    lParamList.Add('Par4=false');

    lHTTP := TIdHTTP.Create(nil);
    try
      lHTTP.Post('https://www.rumo.com.br/sistema/adm/APILogon.asp', lParamList, Response);
    finally
      lHTTP.Free;
    end;
  finally
    lParamList.Free;
  end;
end;

var
  XML: TMemoryStream;
  Doc: IXMLDocument;
begin
  XML := TMemoryStream.Create;
  try
    ExecuteAPI(XML);
    XML.Position := 0;
    {Memo1.Lines.LoadFromStream(XML);
    XML.Position := 0;}
    Doc := TXMLDocument.Create(nil);
    Doc.LoadFromStream(XML);
  finally
    XML.Free;
  end;
  // use Doc as needed...
end;

If you let TIdHTTP.Post() return the XML as a String, TIdHTTP will try to figure out the XML's charset by analyzing the HTTP Content-Type header, and potentially also the XML's own prolog declaration, and then decode the raw data to Unicode based on that charset, and then re-encode the Unicode data to a String (which will be either Ansi or Unicode depending on your version of Delphi). That first step is error-prone and could cause data loss, for instance if the HTTP server is misconfigured. It is better to have TIdHTTP.Post() return the raw XML data and let an XML parser handle the charset decoding. That is part of its job, afterall.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • While David posted the correct answer to this simple question, IMHO this answer should be the most upvoted one :) – whosrdaddy Jan 06 '16 at 19:12
  • I appreciate the HTML tags tip, and it is actually how we should not do it. But does the server interprets the request as in XML format? The rest of your post will be useful in the next steps of developing my application, I really thank you for your time. – André D Palhares Jan 07 '16 at 01:44
  • The *request* is not in any XML format, no. It is submitted in `application/x-www-webform-urlencoded` format (since you are simulating a submission of an HTML webform). If you want to post an actual XML document, post the XML data using a `TStream`-derived object instead of a `TStringList`, the stream data will be posted as-is. – Remy Lebeau Jan 07 '16 at 02:06
  • It was a misunderstood from my part... now, everything works and I can view the response in the Memo. Of course this is for "debugging purposes" and, as you suggested, my application will be picking parts of the XML and throwing them into EditBoxes for further processing. – André D Palhares Jan 08 '16 at 13:49
2

How can I view it, for example, by filling a TMemo?

To view text in a memo control, assign to the Text property:

Memo1.Text := ExecuteAPI;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490