Einzelnen Beitrag anzeigen

Schokohase
(Gast)

n/a Beiträge
 
#2

AW: post Json mit REST

  Alt 22. Okt 2018, 19:39
Wenn ich mit einer REST API sprechen muss, dann erstelle ich mir dafür einen passenden Client. Dieses Zusammengebau-Gefrickel ist nicht so mein Ding.

Hier mal ein kleines Beispiel, wie so etwas aussehen kann (mit 2 Endpoints und jeweils einer POST Methode):
Delphi-Quellcode:
unit Magento.v2_3;

interface

uses
  System.Classes, System.SysUtils, System.Net.HttpClient, System.JSON,
  REST.Json, REST.Json.Types;

type
  EMagento2ClientException = class( Exception )
  end;

  TMagento2Client = class;

  TMagento2EndpointBase = class abstract
  public type
    TErrorResponse = class
    public type
      TParameterItem = class
      private
        [JsonName( 'resources' )]
        FResources: string;
        [JsonName( 'fieldName' )]
        FFieldName: string;
        [JsonName( 'fieldValue' )]
        FFieldValue: string;
      public
        property Resources: string read FResources write FResources;
        property FieldName: string read FFieldName write FFieldName;
        property FieldValue: string read FFieldValue write FFieldValue;
      end;

      TParameters = TArray<TParameterItem>;

      TErrorItem = class
      private
        [JsonName( 'message' )]
        FMessage: string;
        [JsonName( 'parameters' )]
        FParameters: TParameters;
      public
        destructor Destroy; override;
      public
        property &Message: string read FMessage write FMessage;
        property Parameters: TParameters read FParameters write FParameters;
      end;

      TErrors = TArray<TErrorItem>;
    private
      [JsonName( 'message' )]
      FMessage: string;
      [JsonName( 'errors' )]
      FErrors: TErrors;
      [JsonName( 'code' )]
      FCode: Integer;
      [JsonName( 'trace' )]
      FTrace: string;
      [JsonName( 'parameters' )]
      FParameters: TParameters;
    public
      destructor Destroy; override;
    public
      property &Message: string read FMessage write FMessage;
      property Errors: TErrors read FErrors write FErrors;
      property Code: Integer read FCode write FCode;
      property Parameters: TParameters read FParameters write FParameters;
      property Trace: string read FTrace write FTrace;
    end;

  private
    [weak]
    FClient: TMagento2Client;
  protected
    property Client: TMagento2Client read FClient;
  protected
    procedure CheckResponse( const AResponse: IHttpResponse );
    function GetUrlFromBase( const ARelativePath: string ): string;
  public
    constructor Create( AClient: TMagento2Client );
  end;

  TIntegrationAdminTokenServiceV1 = class( TMagento2EndpointBase )
  public type
    TCreateAdminAccessTokenPostBody = class
    private
      [JsonName( 'username' )]
      FUsername: string;
      [JsonName( 'password' )]
      FPassword: string;
    public
      property Username: string read FUsername write FUsername;
      property Password: string read FPassword write FPassword;
    end;

  public
    function CreateAdminAccessToken( const ABody: TCreateAdminAccessTokenPostBody ): string;
  end;

  TIntegrationCustomerTokenServiceV1 = class( TMagento2EndpointBase )
  public type
    TCreateCustomerAccessTokenPostBody = class
    private
      [JsonName( 'username' )]
      FUsername: string;
      [JsonName( 'password' )]
      FPassword: string;
    public
      property Username: string read FUsername write FUsername;
      property Password: string read FPassword write FPassword;
    end;
  public
    function CreateCustomerAccessToken( const ABody: TCreateCustomerAccessTokenPostBody ): string;
  end;

  TMagento2Client = class
  private
    FBaseUrl: string;
    FAccessToken: string;
    FHttpCLient: THttpClient;
    FIntegrationAdminTokenServiceV1: TIntegrationAdminTokenServiceV1;
    FIntegrationCustomerTokenServiceV1: TIntegrationCustomerTokenServiceV1;
    function GetHttpClient: THttpClient;
    procedure SetAccessToken( const Value: string );
    procedure SetBaseUrl( const Value: string );
    function GetIntegrationAdminTokenServiceV1: TIntegrationAdminTokenServiceV1;
    function GetIntegrationCustomerTokenServiceV1: TIntegrationCustomerTokenServiceV1;
  protected
    property HttpClient: THttpClient read GetHttpClient;
  public
    destructor Destroy; override;
  public
    property BaseUrl: string read FBaseUrl write SetBaseUrl;
    property AccessToken: string read FAccessToken write SetAccessToken;

    property IntegrationAdminTokenServiceV1: TIntegrationAdminTokenServiceV1 read GetIntegrationAdminTokenServiceV1;
    property IntegrationCustomerTokenServiceV1: TIntegrationCustomerTokenServiceV1 read GetIntegrationCustomerTokenServiceV1;
  end;

type
  TUtils = class
  protected
    class procedure FreeArrayItems<T: class>( var AObjectArray: array of T );
  end;

implementation

{ TMagento2EndpointBase.TErrorResponse }

destructor TMagento2EndpointBase.TErrorResponse.Destroy;
begin
  TUtils.FreeArrayItems<TMagento2EndpointBase.TErrorResponse.TErrorItem>( FErrors );
  TUtils.FreeArrayItems<TMagento2EndpointBase.TErrorResponse.TParameterItem>( FParameters );
  inherited;
end;

{ TUtils }

class procedure TUtils.FreeArrayItems<T>( var AObjectArray: array of T );
var
  I: Integer;
  obj: T;
begin
  for I := Low( AObjectArray ) to High( AObjectArray ) do
    begin
      obj := AObjectArray[I];
      AObjectArray[I] := nil;
      obj.Free( );
      obj := nil;
    end;
end;

{ TMagento2EndpointBase.TErrorResponse.TErrorItem }

destructor TMagento2EndpointBase.TErrorResponse.TErrorItem.Destroy;
begin
  TUtils.FreeArrayItems<TMagento2EndpointBase.TErrorResponse.TParameterItem>( FParameters );
  inherited;
end;

{ TMagento2EndpointBase }

procedure TMagento2EndpointBase.CheckResponse( const AResponse: IHttpResponse );
var
  e: TErrorResponse;
begin
  if ( AResponse.StatusCode >= 400 )
  then
    begin
      e := TJson.JsonToObject<TErrorResponse>( AResponse.ContentAsString( ) );
      raise EMagento2ClientException.Create( e.Message );
    end;
end;

constructor TMagento2EndpointBase.Create( AClient: TMagento2Client );
begin
  inherited Create;
  if not Assigned( AClient )
  then
    raise EArgumentNilException.Create( 'AClient' );

  FClient := AClient;
end;

function TMagento2EndpointBase.GetUrlFromBase( const ARelativePath: string ): string;
begin
  Result := Client.BaseUrl + ARelativePath;
end;

{ TIntegrationAdminTokenServiceV1 }

function TIntegrationAdminTokenServiceV1.CreateAdminAccessToken( const ABody: TCreateAdminAccessTokenPostBody ): string;
var
  url: string;
  body: string;
  source: TStream;
  reqs: IHttpRequest;
  resp: IHttpResponse;
  v: TJsonValue;
begin
  if not Assigned( ABody )
  then
    raise EArgumentNilException.Create( 'ABody' );

  url := GetUrlFromBase( 'rest/all/V1/integration/admin/token' );
  body := TJson.ObjectToJsonString( ABody );
  source := TStringStream.Create( body );
  try
    Client.HttpClient.Accept := 'application/json';
    Client.HttpClient.ContentType := 'application/json';

    resp := Client.HttpClient.Post( url, source );
  finally
    source.Free;
  end;

  CheckResponse( resp );

  v := TJSONObject.ParseJSONValue( resp.ContentAsString( ) );
  try
    Result := TJsonString( v ).Value;
  finally
    v.Free;
  end;
end;

{ TMagento2Client }

destructor TMagento2Client.Destroy;
begin
  FreeAndNil( FIntegrationAdminTokenServiceV1 );
  FreeAndNil( FIntegrationCustomerTokenServiceV1 );
  FreeAndNil( FHttpCLient );
  inherited;
end;

function TMagento2Client.GetHttpClient: THttpClient;
begin
  if not Assigned( FHttpCLient )
  then
    FHttpCLient := THttpClient.Create( );

  Result := FHttpCLient;
end;

function TMagento2Client.GetIntegrationAdminTokenServiceV1: TIntegrationAdminTokenServiceV1;
begin
  if not Assigned( FIntegrationAdminTokenServiceV1 )
  then
    FIntegrationAdminTokenServiceV1 := TIntegrationAdminTokenServiceV1.Create( Self );

  Result := FIntegrationAdminTokenServiceV1;
end;

function TMagento2Client.GetIntegrationCustomerTokenServiceV1: TIntegrationCustomerTokenServiceV1;
begin
  if not Assigned( FIntegrationCustomerTokenServiceV1 )
  then
    FIntegrationCustomerTokenServiceV1 := TIntegrationCustomerTokenServiceV1.Create( Self );

  Result := FIntegrationCustomerTokenServiceV1;
end;

procedure TMagento2Client.SetAccessToken( const Value: string );
begin
  FAccessToken := Value;

  if string.IsNullOrWhiteSpace( FAccessToken )
  then
    HttpClient.CustomHeaders['Authorization'] := string.Empty
  else
    HttpClient.CustomHeaders['Authorization'] := 'Bearer ' + Value;
end;

procedure TMagento2Client.SetBaseUrl( const Value: string );
begin
  FBaseUrl := Value;
end;

{ TIntegrationCustomerTokenServiceV1 }

function TIntegrationCustomerTokenServiceV1.CreateCustomerAccessToken( const ABody: TCreateCustomerAccessTokenPostBody ): string;
var
  url: string;
  body: string;
  source: TStream;
  reqs: IHttpRequest;
  resp: IHttpResponse;
  v: TJsonValue;
begin
  if not Assigned( ABody )
  then
    raise EArgumentNilException.Create( 'ABody' );

  url := GetUrlFromBase( 'rest/all/V1/integration/customer/token' );
  body := TJson.ObjectToJsonString( ABody );
  source := TStringStream.Create( body );
  try
    Client.HttpClient.Accept := 'application/json';
    Client.HttpClient.ContentType := 'application/json';

    resp := Client.HttpClient.Post( url, source );
  finally
    source.Free;
  end;

  CheckResponse( resp );

  v := TJSONObject.ParseJSONValue( resp.ContentAsString( ) );
  try
    Result := TJsonString( v ).Value;
  finally
    v.Free;
  end;
end;

end.
und die Verwendung
Delphi-Quellcode:
var
  clt: TMagento2Client;
  accessToken: string;
  body: TIntegrationAdminTokenServiceV1.TCreateAdminAccessTokenPostBody;
begin
  clt := TMagento2Client.Create;
  try
    clt.BaseUrl := 'http://localhost/magento2/';
    body := TIntegrationAdminTokenServiceV1.TCreateAdminAccessTokenPostBody.Create;
    try
      body.Username := 'admin';
      body.Password := 'secret';
      accessToken := clt.IntegrationAdminTokenServiceV1.CreateAdminAccessToken( body );
    finally
      body.Free;
    end;
    clt.accessToken := accessToken;
    Writeln( accessToken );
  finally
    clt.Free;
  end;
end;
  Mit Zitat antworten Zitat