![]() |
post Json mit REST
Ich solle per Rest eine Json-Objekt per Post an einen Server schicken. Beispiele zum empfangen von Json-Objekten gibts viele... zum Senden nicht.
Von derem Server kommt immer zurück "invalid json primitive". Verwundert bin ich obwohl in der Komponenten ContentType := 'application/json' ist der ContentType nach dem execute wieder "application/x-www-form-urlencoded" Das passiert auch wenn ich im Designer den Requset per Hand ausführe Vom Support dort kommt: Zitat:
Delphi-Quellcode:
procedure TFormRESTTest.BtnAbwertenClick(Sender: TObject);
var jValue, jApixResponse: TJSONValue; jUpdates: TJSONArray; hash : system.hash.THashSHA2; AuthToken: string; Stringwriter : TStringWriter; Writer : Tjsontextwriter; Builder : tjsonobjectbuilder; Str, Zeit,Datum, DatumZeit : string; Ammount : string; begin memo.Clear; Ammount:='-'+EDBetrag.Text; if (AccountID<>'') and (AccountID<>'keine Karte') then begin System.SysUtils.DateTimeToString(Datum,'yyyy-mm-dd',now); // Zeit im Format yyyy-mm-ddThh-nn-ssZ System.SysUtils.DateTimeToString(Zeit,'hh-nn-ss',now); DatumZeit:=Datum+'T'+Zeit+'Z'; hash.Reset; AuthToken:=hash.GetHashString(AppID+'-'+AccountInfo.AccountID+'-1-'+Ammount+'-'+DatumZeit); Stringwriter:=TStringWriter.Create(); Writer:=TJsonTextWriter.Create(Stringwriter); Builder:=TJSONObjectBuilder.Create(Writer); Builder .BeginObject .BeginObject('ApiXRequest') .Add('Hash', AuthToken) ..... .EndObject .EndObject; jValue:= TJSONObject.Create; jValue:= TJSONObject.ParseJSONValue(Stringwriter.ToString,true); Builder.Free; Writer.Free; Stringwriter.Free; Memo.lines.Add('-> '+jValue.ToString); Req_Update.Params.Clear; RESTWay2PAy.ContentType := 'application/json'; Req_Update.Params.AddItem('ApiXRequest',jValue.ToString,pkGETorPOST,[poDoNotEncode]); Req_Update.Execute; if Res_Update.StatusCode = 200 then begin jValue:=Res_Update.JSONValue; Memo.lines.Add('<- '+ jValue.ToString); jApixResponse:=jValue.GetValue<TJSONObject>('ApixResponse'); AccountInfo.AccountStatus:=jApixResponse.GetValue<Integer>('Status'); jUpdates:=jApixResponse.GetValue<TJSONArray>('Updates'); ...... LBLGuthaben.Caption:=BalanceStr; LBLGruppe.Caption:=IntToStr(AccountInfo.DepartmentID1); AccountInfo.PurseBalance:=strtoint(BalanceStr); end else begin ShowMessage('Fehler :'+inttostr(Res_Update.StatusCode)); Memo.lines.Add('<- '+ Res_Update.Content); end; end; end; |
AW: post Json mit REST
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:
und die Verwendung
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.
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; |
AW: post Json mit REST
Hui, den ganzen JSON-Request in den Parameter zu packen, ist aber auch mutig. ;-)
Hier mal ein kleiner Ausschnitt, wie man es machen könnte und die Anfrage mittels eines TRESTRequest loswerden kann:
Delphi-Quellcode:
Vielleicht hilft dir das weiter.[...] type TmyClass = class [...] RestRequest: TRESTRequest; procedure SendData (...); end; [...] procedure TmyClass.SendData (...); var jWriter: TJsonTextWriter; begin jWriter:=TJsonTextWriter.Create(TStringWriter.Create); try jWriter.WriteStartObject; // hier nur ein einfaches Objekt mit zwei Feld/Wert-Paaren jWriter.WritePropertyName('headFields'); jWriter.WriteValue('wuppdi'); jWriter.WritePropertyName('tableFields'); jWriter.WriteValue('foobar'); jWriter.WriteEndObject; RestRequest.Method:=rmPOST; RestRequest.AddBody(jWriter.Writer.ToString,ctAPPLICATION_JSON); RestRequest.Resource:='/location/to/change/data'; RestRequest.Execute; except [... Fehlerbehandlung ...] end; [...] jWriter.Writer.Free jWriter.Free; end; Anstelle des jWriters, wie ich das hier gemacht habe, kannst du den Json-String sicherlich genauso auch mit dem jBuilder zusammenbasteln. Hauptsache im Body vom RestRequest landet der String. :-) |
AW: post Json mit REST
Mit einem JSON Online Validator den Request auf gültiges JSON prüfen.
![]() |
AW: post Json mit REST
Zitat:
Bei REST wird ein POST-Request ohne Felder verwendet sondern einfach als Payload. Feldnamen braucht man ja auch nicht, steckt ja im JSON drin. Gesendet werden folgende Dinge via TCP: HTTP-Header, zwei Windows-Absätze, JSON-String. Kann man theoretisch auch einfach von Hand machen. Komplettes Programm (nicht geprüft, da hier mal eben im Editor geschrieben):
Delphi-Quellcode:
var
TCP: TIdTCPClient; Header: AnsiString; Payload: RawByteString; begin Payload := UTF8Encode(JSON); Header := 'POST / HTTP/1.0'#13#10'Host: example.com'#13#10'Content-Type: application/json'#13#10'Content-Length: ' + IntToStr(Length(Payload)) + #13#10'IRGENDWELCHE HEADER HIER'#13#10#13#10; TCP := TIdTCPClient.Create(); TCP.Host := '127.0.0.1'; TCP.Port := 80; TCP.Connect(); TCP.IOHandler.Write(Header[1], Length(Header)); TCP.IOHandler.Write(Payload[1], Length(Payload)); Result := TCP.IOHandler.AllData(); end; |
AW: post Json mit REST
Hallo und vielen Dank für die Posts.
@Edelfix: Die Json Objekte sind mit Sourcecode den mir das JsonWorkbench aus den RADStudioDemos erstellt hat und daher vaild. (ccoles Tool) Der Witz an der Sache war, dass die Fima countersolutions.co.uk obwohl die URL zum Post was mit RestAPI ist, einen nackten HTTP-Post erwartet bei dem das Json-Obekt als Payload dran hängt. Ich schaffe jetzt eine Kommunikation im Prinzip wie es Schokohase gemacht hat:
Delphi-Quellcode:
procedure TFormRESTTest.Button1Click(Sender: TObject);
var body: string; source: TStream; reqs: IHttpRequest; resp: IHttpResponse; Client: THttpClient; begin body := JsonUpate('10',AccountID); source := TStringStream.Create( body ); Client:=THttpClient.Create( ); // Client.ContentType := 'application/json'; resp := Client.Post( BaseURL+'AccountPurses', source ); if ( resp.StatusCode >= 400 ) then begin ShowMessage('Fehler: '+inttostr(resp.StatusCode)); end; Memo.lines.add(resp.ContentAsString); end; Mit der Indy Library habe ich es nicht geschafft da dort immer der Wert accept gesetzt wird selbst wenn die Property leer ist: "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" Allein das reicht damit der Server mit Bad Request antwortet. Sonst sieht das Paket gleich aus im Wireshark. |
AW: post Json mit REST
Zitat:
|
AW: post Json mit REST
Zitat:
|
AW: post Json mit REST
Zitat:
|
AW: post Json mit REST
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:29 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz