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:
number
- which stands for a 13 digit number that represents the unique file indicator in their system (example: 5277110610029)username
anduser_pass
respectively - which stand for the login credentials to access the systemclient_id
- which stands for a unique client ID associated with my account in their systemlanguage
- where I indicate the language the file contents should be in (English or other of the available languages)
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"
- What am I doing wrong? / How do you properly save a Post requests that returns a .pdf file to download from the API?
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.
- Is my code not the correct approach to Post and save the file being sent?
CodePudding user response:
If I try the resulting
URL
andparameters
in the browser - it auto-downloads thenumberParameter.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:
the HTTP server is NOT reporting an error at the HTTP level, ie it is sending the text message using an HTTP
2xx
success response. I suspect this is what is happening in your case. By default, if the server uses a proper HTTP error code,TIdHTTP
will raise anEIdHTTPProtocolException
containing the text message and NOT save the text to yourTMemoryStream
at all.the HTTP server IS reporting an error at the HTTP level, but you are using the
hoNoProtocolErrorException
andhoWantProtocolErrorContent
flags together in theTIdHTTP.HTTPOptions
property. In which case,TIdHTTP
would not raiseEIdHTTPProtocolException
and would instead save whatever data the server sends as-is to yourTMemoryStream
.
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.