Recent

Author Topic: Implemeting CURL script with Indy  (Read 799 times)

patyit

  • New Member
  • *
  • Posts: 27
Implemeting CURL script with Indy
« on: July 14, 2022, 10:05:27 am »
Hi all !

Please help me implement this CURL script with Indy:

curl -X POST "https://efakturatest.mfin.gov.rs/api/publicApi/sales-
invoice/ubl/upload?requestId=061720221143-upl&sendToCir=No" -H "accept: text/plain" -H
"ApiKey: d7114d70-14ca-40fe-a840-807c5353fd16" -H "Content-Type: multipart/form-data" -F
"ublFile=@TAM721TEST-test.xml;type=text/xml"

I am trying this code but I don't know how to add
-F "ublFile=@TAM721TEST-test.xml;type=text/xml" script segment.

Code: Pascal  [Select][+][-]
  1. function sales_invoice_ubl_upload(url, key, ubl, rid: string): string;
  2. var
  3.   idHttp : TIdHTTP;
  4.   par : TStringlist;
  5.   res : string;
  6. begin
  7.   Result := '';
  8.   idHttp := TIdHTTP.Create;
  9.   try
  10.     idHttp.HandleRedirects := False;
  11.     idHttp.ReadTimeout     := 30000;
  12.     idHttp.Request.Accept  := 'text/plain';
  13.     idHttp.Request.ContentType := 'multipart/form-data';
  14.     idHttp.Request.CustomHeaders.Add('ApiKey: '+key);
  15.  
  16.     par := TStringList.Create;
  17.     try
  18.       par.Add('RequestId='+rid);
  19.       par.Add('sendToCir=No');
  20.       try
  21.         url += '/api/publicApi/sales-invoice/ubl/upload';
  22.         ubl := '"ublFile=@TAM721TEST-test.xml;type=text/xml"';
  23.         res := idHttp.Post(url, ubl);
  24.         if idHttp.ResponseCode = 200 then
  25.           Result := res
  26.         else if idHttp.ResponseCode = 400 then
  27.           MessageDlg('Request Error  !'+#13#13+
  28.                       IntToStr(IdHttp.ResponseCode)+' '+
  29.                       idHttp.ResponseText, mtError, [mbOk], 0)
  30.         else
  31.           MessageDlg('Error: '+IntToStr(IdHttp.ResponseCode)+' '+
  32.                       idHttp.ResponseText, mtError, [mbOk], 0);
  33.       except
  34.         on E: Exception do begin
  35.           Result := '';
  36.           MessageDlg('Check internet connection ...'+#13#13+
  37.                       E.Message, mtError, [mbOk], 0);
  38.         end;
  39.       end;
  40.     finally
  41.       par.Free;
  42.     end;
  43.   finally
  44.     idHttp.Free;
  45.     Sleep(200);
  46.   end;
  47. end;        
  48.  

patyit

  • New Member
  • *
  • Posts: 27
Re: Implemeting CURL script with Indy
« Reply #1 on: July 14, 2022, 10:43:48 am »
I modified the code a bit
Code: Pascal  [Select][+][-]
  1. function sales_invoice_ubl_upload(url, key, ubl, rid: string): string;
  2. var
  3.   idHttp : TIdHTTP;
  4.   req : TStringStream;
  5.   res : string;
  6. begin
  7.   idHttp := TIdHTTP.Create;
  8.   try
  9.     idHttp.HandleRedirects := False;
  10.     idHttp.ReadTimeout     := 30000;
  11.     idHttp.Request.Accept  := 'text/plain';
  12.     idHttp.Request.ContentType := 'multipart/form-data';
  13.     idHttp.Request.CustomHeaders.Add('ApiKey: '+key);
  14.     try
  15.       // can i specify such parameters in the url ?
  16.       url := url+'/api/publicApi/sales-invoice/ubl/upload?RequestId='+rid+'&sendToCir=No';
  17.       // is it correct to define xml and file type ?
  18.       ubl := '"ublFile=@'+ubl+';type=text/xml"'; // ?????
  19.       res := idHttp.Post(url, ubl);
  20.       if idHttp.ResponseCode = 200 then
  21.         Result := res
  22.       else if idHttp.ResponseCode = 400 then begin
  23.         Result := '';
  24.         MessageDlg('Request Error  !'+#13#13+
  25.                     IntToStr(IdHttp.ResponseCode)+' '+
  26.                     idHttp.ResponseText, mtError, [mbOk], 0)
  27.       end else begin
  28.         Result := '';
  29.         MessageDlg('Error: '+IntToStr(IdHttp.ResponseCode)+' '+
  30.                     idHttp.ResponseText, mtError, [mbOk], 0);
  31.       end;
  32.     except
  33.       on E: Exception do begin
  34.         Result := '';
  35.         MessageDlg('Check the Internet connection ...'+#13#13+
  36.                     E.Message, mtError, [mbOk], 0);
  37.       end;
  38.     end;
  39.   finally
  40.     idHttp.Free;
  41.     Sleep(200);
  42.   end;
  43. end;        
  44.  

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Implemeting CURL script with Indy
« Reply #2 on: July 14, 2022, 11:40:05 am »
-F sends a FORM body in the POST request, where @ references a local file.
So what you have to do is to read the file TAM721TEST-test.xml and either construct the form content yourself (by url encoding the data and creating a key-value list in the form format), or simply by putting the data in a key-value string list and passing it to the .Post method of IdHTTP

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1314
    • Lebeau Software
Re: Implemeting CURL script with Indy
« Reply #3 on: July 14, 2022, 10:26:58 pm »
Please help me implement this CURL script with Indy:

You are calling TIdHTTP.Post() with a filename as a parameter, which will POST the contents of that file as-is as the entire HTTP request body.  That is not what you need in this situation.

So what you have to do is to read the file TAM721TEST-test.xml and either construct the form content yourself (by url encoding the data and creating a key-value list in the form format) or simply by putting the data in a key-value string list and passing it to the .Post method of IdHTTP

That is the wrong advice in this situation.  You can clearly see in the curl example that the request needs to be in multipart/form-data format, but what you suggest will send the request in application/x-www-form-urlencoded format instead.

TIdHTTP.Post() has an overload which takes a TIdMultipartFormDataStream to handle multipart/form-data requests, eg:

Code: Pascal  [Select][+][-]
  1. function sales_invoice_ubl_upload(url, key, ubl, rid: string): string;
  2. var
  3.   idHttp : TIdHTTP;
  4.   postData: TIdMultipartFormDataStream;
  5. begin
  6.   Result := '';      
  7.   idHttp := TIdHTTP.Create;
  8.   try
  9.     idHttp.HandleRedirects := False;
  10.     idHttp.ReadTimeout     := 30000;
  11.     idHttp.Request.Accept  := 'text/plain';
  12.     idHttp.Request.ContentType := 'multipart/form-data';
  13.     idHttp.Request.CustomHeaders.Values['ApiKey'] := key;
  14.  
  15.     postData := TIdMultipartFormDataStream.Create;
  16.     try
  17.       url := url + '/api/publicApi/sales-invoice/ubl/upload?requestId=' + TIdURI.ParamsEncode(rid) + '&sendToCir=No';
  18.       postData.AddFile('ublFile', ubl, 'text/xml');
  19.       try
  20.         Result := idHttp.Post(url, postData);
  21.       except
  22.         on E: EIdHTTPProtocolException do begin
  23.           if E.ErrorCode = 400 then
  24.             MessageDlg('Request Error  !'+#13#13+
  25.                         IntToStr(E.ErrorCode) + ' ' + E.Message,
  26.                         mtError, [mbOk], 0)
  27.           else
  28.             MessageDlg('Error: '+IntToStr(E.ErrorCode) + ' ' + E.Message,
  29.                         mtError, [mbOk], 0);
  30.         end;
  31.         on E: Exception do begin
  32.           MessageDlg('Check the Internet connection ...'+#13#13+
  33.                     E.Message, mtError, [mbOk], 0);
  34.         end;
  35.       end;
  36.     finally
  37.       postData.Free;
  38.     end;
  39.   finally
  40.     idHttp.Free;
  41.     Sleep(200);
  42.   end;
  43. end;        
  44.  

Also note that I moved the handling of the HTTP response code inside of the except block.  By default, TIdHTTP raises EIdHTTPProtocolException if the HTTP response code indicates the request failed.  If you want to handle the TIdHTTP.ResponseCode yourself without raising the exception, you would need to specify the hoNoProtocolErrorException flag in the TIdHTTP.HTTPOptions property, eg:

Code: Pascal  [Select][+][-]
  1. function sales_invoice_ubl_upload(url, key, ubl, rid: string): string;
  2. var
  3.   idHttp : TIdHTTP;
  4.   postData: TIdMultipartFormDataStream;
  5.   res: string;
  6. begin
  7.   Result := '';      
  8.   idHttp := TIdHTTP.Create;
  9.   try
  10.     idHttp.HandleRedirects := False;
  11.     idHttp.ReadTimeout     := 30000;
  12.     idHttp.Request.Accept  := 'text/plain';
  13.     idHttp.Request.ContentType := 'multipart/form-data';
  14.     idHttp.Request.CustomHeaders.Values['ApiKey'] := key;
  15.     idHttp.HTTPOptions := idHttp.HTTPOptions + [hoNoProtocolErrorException];
  16.  
  17.     postData := TIdMultipartFormDataStream.Create;
  18.     try
  19.       url := url + '/api/publicApi/sales-invoice/ubl/upload?requestId=' + TIdURI.ParamsEncode(rid) + '&sendToCir=No';
  20.       postData.AddFile('ublFile', ubl, 'text/xml');
  21.       try
  22.         res := idHttp.Post(url, postData);
  23.         if idHttp.ResponseCode = 200 then
  24.           Result := res
  25.         else if idHttp.ResponseCode = 400 then
  26.           MessageDlg('Request Error  !'+#13#13+
  27.                       IntToStr(idHttp.ResponseCode) + ' ' + idHttp.ResponseText,
  28.                       mtError, [mbOk], 0)
  29.         else
  30.           MessageDlg('Error: '+IntToStr(idHttp.ResponseCode) + ' ' + idHttp.ResponseText,
  31.                       mtError, [mbOk], 0);
  32.       except
  33.         on E: Exception do begin
  34.           MessageDlg('Check the Internet connection ...'+#13#13+
  35.                     E.Message, mtError, [mbOk], 0);
  36.         end;
  37.       end;
  38.     finally
  39.       postData.Free;
  40.     end;
  41.   finally
  42.     idHttp.Free;
  43.     Sleep(200);
  44.   end;
  45. end;        
  46.  
« Last Edit: July 14, 2022, 10:45:54 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

patyit

  • New Member
  • *
  • Posts: 27
Re: Implemeting CURL script with Indy
« Reply #4 on: July 15, 2022, 11:32:09 am »
Thank you for your help Remy, (the intention for Warfley as well), I will try the suggested code and let you know the result !

 

TinyPortal © 2005-2018