0

I am programming in Delphi and I'm having a hard time converting a C++ API POST Request into delphi. I have tried using Indy as I have before with previous API's but this one seems to not work with whatever I try. Could someone help me with this?

C++ Code I need to convert:

CURL *hnd = curl_easy_init();

curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_URL, "https://sandbox.checkbook.io/v3/check/digital");

struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "accept: application/json");
headers = curl_slist_append(headers, "content-type: application/json");
headers = curl_slist_append(headers, "Authorization: xxxxxxxxxxxxxxxx:xxxxxxxxxxxxxxxxx");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);

curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, "{\"recipient\":\"[email protected]\",\"name\":\"Widgets Inc.\",\"amount\":5,\"description\":\"Test Payment\"}");

CURLcode ret = curl_easy_perform(hnd);

Delphi Code that I have:

unit API_InvoiceCloud;

interface

uses
  DB, SysUtils,  System.Classes, System.JSON, IdSSLOpenSSL, VCL.Dialogs,
  IdHTTP, XML.XMLIntf, xml.xmlDom, xml.XMLDoc, IDCoder, IDCoderMIME,
  IdBaseComponent, IdException{, IdZLibCompressorBase{, IdCompressorZLib{,Rest.Client};

procedure CreateDigitalPayment_CheckBookAPI(mRecipientEmailAddress,
                                      mRecipientName : String;
                                      mPaymentAmount : Double;
                                      mPaymentNumber,
                                      mPaymentDescription : String);


implementation

var
  { INDY COMPONENT TO CONNECT TO API SERVER; MAKES CONNECTION }
  IDHTTP1 : TidHttp;
  { SSL Connection }
  SSL : TIdSSLIOHandlerSocketOpenSSL;
  { Request and Response vars }
  JsonRequest, InJson : String;
  JsonToSend : TStringStream;    //object to store json text and pass API
  JObj : TJSONObject;
Const
  { Constant variables holding the APIKEY+APISECRET and BASEURL }
  nBASEURL = 'https://sandbox.checkbook.io/v3/check/digital';
  nAPIKEY = 'xxxxxxxxx:xxxxxxxx';

procedure CreateDigitalPayment_CheckBookAPI(mRecipientEmailAddress,
                                            mRecipientName : String;
                                            mPaymentAmount : Double;
                                            mPaymentNumber,
                                            mPaymentDescription : String);
var
  { Response into String }
  SinglePartyResponse : String;
  ResponseCode : String;  
  { -----------Testing---------- }
  //lParamList: TStringList;
  nBASEURL : String;
  RequestBody : TStream;
  ResponseBody : String;
begin
  
  { JSON body with request string }
  JsonRequest := '{"recipient":"' + mRecipientEmailAddress
                + '","name":"' + mRecipientName
                + '","amount":' + FloatToStr(mPaymentAmount)
                + ',"number":"' + mPaymentNumber
                + '","description":"' + mPaymentDescription + '"}';
  
  try

    try
      { Create connection instance }
      IDHTTP1 := TidHttp.Create;

      { SSL Configuration }
      SSL := TIdSSLIOHandlerSocketOpenSSL.Create;
      SSL.SSLOptions.SSLVersions := [sslvTLSv1_1, sslvTLSv1_2];
      IDHTTP1.IOHandler := SSL;

      { Headers/Params }
      IDHTTP1.Request.Clear;
      IDHTTP1.Request.CustomHeaders.FoldLines := False;
      IDHTTP1.Request.Accept := 'application/json';
      IDHTTP1.Request.ContentType := 'application/json';
      IDHTTP1.Request.CustomHeaders.Values['Authorization'] := nAPIKEY;
      
      { Saving JSON text to TStringStream Object }
      JsonToSend := TStringStream.Create(JsonRequest, TEncoding.UTF8);
      //JsonToSend := TStringStream.Create(JsonRequest, TEncoding.ASCII);

      { Making POST Request using INDYs TidHTTP component; Params are: URL, JsonStringObj - saving into variable }
      SinglePartyResponse := IDHTTP1.Post(nBASEURL, JsonToSend);
      
      ShowMessage(IDHTTP1.ResponseCode.ToString);

    except
      on E : Exception do
        { Display error message if cannot do API CALL }
        begin
          ShowMessage(E.ClassName+' error raised, with message : "' + E.Message + '".');
          Abort;
        end
    end;

  finally
    { Free objects from memory }
    IDHTTP1.Free;
    SSL.Free;
    JsonToSend.Free;
  end;
  
end;

end.

When I try to make the POST request I get a 400 Bad Request error. I'm not sure what I am doing wrong here.

8
  • 1
    Change the endpoints to a server under your control and compare the requests? Commented Nov 21, 2022 at 15:22
  • cross-posted here: en.delphipraxis.net/topic/… Commented Nov 21, 2022 at 15:44
  • @Botje I do not have access to any of these servers to test this. Commented Nov 21, 2022 at 15:47
  • 2
    Hence "server under your control". Even your laptop suffices. Commented Nov 21, 2022 at 15:49
  • 1
    Off-hand, the code looks correct, as far as TIdHTTP is concerned. So, the most likely culprit is the JSON is probably malformed, ie if one of the text values has a " char in it. Since you have System.JSON in the uses clause, you really should use TJSONObject to create the JSON string, let it handle any necessary escaping as needed. Commented Nov 21, 2022 at 17:09

1 Answer 1

0

Found Solution. Thanks for the suggestions!

The 400 Bad Request Error was due to an "invalid authorization header"

My solution:

1. Went into the Embarcadero built in RestDebugger and got it to work in there by setting the BASEURL, CONTENT-TYPE, AUTHORIZATION(APIKey in Params), and CustomBody.

2. Clicked on the 'Copy Components' button and pasted RESTClient, RESTRequest, RESTResponse onto an empty form.

3. Built the JSON String and passed it as parameter to RESTRequest.AddBody then executed.(Code below)

    RESTRequest.AddBody(JsonStringRequest, ctAPPLICATION_JSON);
    RESTRequest.Execute();
    RESTResponse := RESTRequest.Response; 

There are better ways to do this, but this worked for me.

Sign up to request clarification or add additional context in comments.

Comments

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.