unit Azure.CognitiveServices.Core.HTTP;

interface

uses
  System.Classes, System.JSON, System.Net.HttpClient,
  System.Net.URLClient, System.SysUtils,
  Azure.CognitiveServices.Core.Entities;

type

  TAcsHttpBroker<TRequest, TResponse> = class
  private
    FConfig: IAcsConfiguration;
    FEndpoint: string;
    FProxySettings: TProxySettings;
  protected
    procedure DoCustomizeClient(const ARequest: TRequest; const AClient: THTTPClient); virtual;
    procedure DoCustomizeURI(const ARequest: TRequest; const AURI: TURI); virtual;
    procedure DoCustomizeHeaders(const ARequest: TRequest; var AHeaders: TNetHeaders); virtual;
    procedure DoCustomizeContentType(const ARequest: TRequest; var AContentType: string); virtual;
    procedure DoPrepareRequestStream(const ARequest: TRequest; var AStream: TStream); virtual;
    procedure DoParseResponseJson(const AJSONObject: TJSONObject; out AResponse: TResponse); virtual;
  public
    constructor Create(AConfig: IAcsConfiguration);
    function Execute(ARequest: TRequest): TResponse;
    property Config: IAcsConfiguration read FConfig;
    property Endpoint: string read FEndpoint write FEndpoint;
    property ProxySettings: TProxySettings read FProxySettings write FProxySettings;
  end;

implementation

uses
  Azure.CognitiveServices.Core.Exceptions;

constructor TAcsHttpBroker<TRequest, TResponse>.Create(AConfig: IAcsConfiguration);
begin
  inherited Create;
  FConfig := AConfig;
end;

function TAcsHttpBroker<TRequest, TResponse>.Execute(ARequest: TRequest): TResponse;
var
  LClient: THTTPClient;
  LContentType: string;
  LStream: TStream;
  LURI: TURI;
  LResponse: IHTTPResponse;
  LContentText: string;
  LContentJson: TJSONObject;
  LErrorMessage: string;
  LHeaders: TNetHeaders;
begin

  LURI := TURI.Create(FEndpoint);
  DoCustomizeURI(ARequest, LURI);

  LClient := THTTPClient.Create;
  try

    LClient.ProxySettings := FProxySettings;
    DoCustomizeClient(ARequest, LClient);

    LStream := nil;
    try

      LContentType := 'application/json';
      DoCustomizeContentType(ARequest, LContentType);

      LHeaders := [
        TNameValuePair.Create('Content-Type', LContentType),
        TNameValuePair.Create('Ocp-Apim-Subscription-Key', FConfig.SubscriptionKey)
      ];

      DoCustomizeHeaders(ARequest, LHeaders);

      DoPrepareRequestStream(ARequest, LStream);

      LResponse := LClient.Post(LURI.ToString, LStream, TStream(nil), LHeaders);

      LContentText := LResponse.ContentAsString();

      LContentJson := TJSONObject(TJSONObject.ParseJSONValue(LContentText));
      try
        if LResponse.StatusCode <> 200 then
        begin
          if not LContentJson.TryGetValue<string>('error.message', LErrorMessage) then
            LErrorMessage := LResponse.StatusText;
          raise EAcsHttpException.Create(LResponse.StatusCode, LResponse.StatusText, LErrorMessage);
        end;
        DoParseResponseJson(LContentJson, Result);
      finally
        LContentJson.Free;
      end;

    finally
      if LStream <> nil then
        LStream.Free;
    end;

  finally
    LClient.Free;
  end;

end;

procedure TAcsHttpBroker<TRequest, TResponse>.DoCustomizeClient(
  const ARequest: TRequest; const AClient: THTTPClient);
begin
end;

procedure TAcsHttpBroker<TRequest, TResponse>.DoCustomizeContentType(
  const ARequest: TRequest; var AContentType: string);
begin
end;

procedure TAcsHttpBroker<TRequest, TResponse>.DoCustomizeHeaders(
  const ARequest: TRequest; var AHeaders: TNetHeaders);
begin
end;

procedure TAcsHttpBroker<TRequest, TResponse>.DoCustomizeURI(
  const ARequest: TRequest; const AURI: TURI);
begin
end;

procedure TAcsHttpBroker<TRequest, TResponse>.DoParseResponseJson(
  const AJSONObject: TJSONObject; out AResponse: TResponse);
begin
end;

procedure TAcsHttpBroker<TRequest, TResponse>.DoPrepareRequestStream(
  const ARequest: TRequest; var AStream: TStream);
begin
end;

end.
