Преобразование почтового запроса C++ API в код Delphi

Я программирую в Delphi, и мне трудно преобразовать запрос C++ API POST в delphi. Я пытался использовать Indy, как и раньше, с предыдущими API, но этот, похоже, не работает с тем, что я пытаюсь. Может ли кто-нибудь помочь мне с этим?

Код С++, который мне нужно преобразовать:

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, который у меня есть:

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.

Когда я пытаюсь сделать запрос POST, я получаю ошибку 400 Bad Request. Я не уверен, что я делаю неправильно здесь.

Изменить конечные точки на сервер под вашим контролем и сравнить запросы?

Botje 21.11.2022 16:22

размещено здесь: en.delphipraxis.net/topic/…

David Heffernan 21.11.2022 16:44

@Botje У меня нет доступа ни к одному из этих серверов, чтобы проверить это.

robhercarloz 21.11.2022 16:47

Отсюда и «сервер под вашим контролем». Достаточно даже вашего ноутбука.

Botje 21.11.2022 16:49

Вам не нужен контроль над сервером. И curl, и Indy имеют опции для вывода необработанных данных HTTP, которые передаются туда и обратно. Включите эти параметры. В завитке используйте CURLOPT_VERBOSE. В Indy назначьте компонент TIdLog... свойству TIdHTTP.Intercept

Remy Lebeau 21.11.2022 18:03

На первый взгляд, код выглядит правильно, что касается TIdHTTP. Таким образом, наиболее вероятным виновником является то, что JSON, вероятно, искажен, то есть если в одном из текстовых значений есть символ ". Поскольку у вас есть System.JSON в предложении uses, вам действительно следует использовать TJSONObject для создания строки JSON, пусть она обрабатывает любое необходимое экранирование по мере необходимости.

Remy Lebeau 21.11.2022 18:09

@Botje Простите за невежество, я новичок в языке и API. Но спасибо, попробую. Я сделал фиктивный сервер в почтальоне и попробую то, что вы рекомендовали. Мне просто нужно выяснить, как правильно работать с этим. ХА.

robhercarloz 21.11.2022 18:48

@RemyLebeau Спасибо! И это то, что я понял неправильно, просто не был слишком уверен, поэтому я также попытаюсь использовать TJSONObject, как было предложено.

robhercarloz 21.11.2022 18:50
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
8
129
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Найдено решение. Спасибо за предложения!

Ошибка 400 Bad Request была связана с «неверным заголовком авторизации».

Мое решение:

1. Зашел в Embarcadero, встроенный в RestDebugger, и заставил его работать там, установив BASEURL, CONTENT-TYPE, AUTHORIZATION (APIKey в Params) и CustomBody.

2. Нажал кнопку «Копировать компоненты» и вставил RESTClient, RESTRequest, RESTResponse в пустую форму.

3. Создал строку JSON и передал ее в качестве параметра RESTRequest.AddBody, а затем выполнил. (Код ниже)

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

Есть лучшие способы сделать это, но это сработало для меня.

Другие вопросы по теме