delphiindyindy10idhttp

TIdHTTP Post to API and save response as a .pdf file


I'm calling an API URL with some parameters according to the documentation provided.

The way the API is set up, the response should be an auto-download of a .pdf file.

The parameters are:

Documentation indicates it should be made as a Post request.

I have the following code:

var
FileName : string;
URL: String;
Params: TStringList;
memStream: TMemoryStream;
...

begin
FileName:= MainModule.PDFfileName + '.pdf';

 begin
 URL := 'https://someURL/view_integrated_pdf.php?';
 Params := TStringList.Create;
 memStream := TMemoryStream.Create;

  try
  Params.Add('number='+MainModule.number+'');
  Params.Add('username='+MainModule.User+'');
  Params.Add('client_id='+MainModule.clientID+'');
  Params.Add('user_pass='+MainModule.Pass+'');
  Params.Add('language=en');

  MainModule.IdHTTP.Post(URL, Params, memStream);

  finally
  memStream.SaveToFile(ServerModule.FilesFolderPath+'\pdfs\'+FileName);
  Params.Free;
  memStream.Free;

  end;
 end;

pdfForm.ShowModal();

end;

If I try the resulting URL and parameters in the browser - it auto-downloads the pdf file the API gives me with the name numberParameter.pdf

If I do it in Delphi using the provided code, 8 out of 10 times it saves a pdf file with a 1 KB Size (normally it is between 32 and 100 for the successful file) and when I try to open it in the program using my pdfForm and subsequent viewer, the viewer throws an error "Invalid PDF structure"

UPDATE

As per the comments, opening up the 1kb resulting PDF in Notepad++ displays the contents as simply Error username.

This is puzzling since I checked and the username being passed is accurate + if I paste the exact same URL with parameter values filed, in the browser, it works perfectly and gives me the correct PDF.


Solution

  • If I try the resulting URL and parameters in the browser - it auto-downloads the pdf file the API gives me with the name numberParameter.pdf

    The only way to do that in a browser is to put the parameters in the URL's query component, eg:

    https://someURL/view_integrated_pdf.php?number=...&username=...&client_id=...&user_pass=...&language=en
    

    ... and not in a POST body, as your code is doing. Also, a browser would send a GET request, not a POST request. Unless you are filling in an HTML webform (ie <form action="<URL>" method="POST" ...>) and submitting it. Is that what the API documentation says to do?

    Since you did not provide any details from the documentation about what this server is actually expecting, we can't really tell you whether your code is correct or wrong. But it does seem that your manual tests are contradicting what you claim the documentation says the server is expecting.

    If I do it in Delphi using the provided code, 8 out of 10 times it saves a pdf file with a 1 KB Size (normally it is between 32 and 100 for the successful file) and when I try to open it in the program using my pdfForm and subsequent viewer, the viewer throws an error "Invalid PDF structure"

    From comments, you say your file is receiving a textual error message. TIdHTTP would save such text to your TMemoryStream ONLY IF either:

    Since there is clearly no HTTP exception being raised, you will have to validate the server's response before you can use the downloaded data in your pdfForm, ie by looking at the TIdHTTP.Response.ContentType and/or TIdHTTP.Response.ContentDisposition property to know whether the server actually sent a PDF file or not.

    This is puzzling since I checked and the username being passed is accurate + if I paste the exact same URL with parameter values filed, in the browser, it works perfectly and gives me the correct PDF.

    Well, for one thing, you have a typo in your code: the numberr field needs to be number instead.

    Beyond that, putting the URL in a browser is NOT the same operation that your code is doing, so try changing your code to mimic what you are doing manually, eg:

    uses
      ..., IdGlobalProtocols, IdHTTP, IdURI;
    
    ...
    
    var
      URL : string;
      memStream: TMemoryStream;
    begin
      // All parameters into the URI for a HTTP GET request
      URL := 'https://someURL/view_integrated_pdf.php'
           + '?number=' + TIdURI.ParamsEncode(MainModule.number)
           + '&username=' + TIdURI.ParamsEncode(MainModule.User)
           + '&client_id=' + TIdURI.ParamsEncode(MainModule.clientID)
           + '&user_pass=' + TIdURI.ParamsEncode(MainModule.Pass)
           + '&language=en';
    
      memStream := TMemoryStream.Create;
      try
        MainModule.IdHTTP.Get(URL, memStream);
    
        // Is it really PDF? Other formats such as plaintext is not wanted.
        if not IsHeaderMediaType(MainModule.IdHTTP.ContentType, 'application/pdf') then Exit;
    
        memStream.SaveToFile(ServerModule.FilesFolderPath + '\pdfs\' + MainModule.PDFfileName + '.pdf');
      finally
        memStream.Free;
      end;
    
      pdfForm.ShowModal;
    end;
    

    If that does not work, then please update your question to provide the actual documentation.