I am trying to use Delphi XE8 RESTClient,RESTRequest and RESTResponse to optain the content of the response to the following API call:
https://api.hubapi.com/contacts/v1/lists/all/contacts/all?hapikey=Demo&count=1000
The call runs fine in C# and in a webbrowser.
I'm not sure how to configure RESTClient and RESTRequest properties.
Can anyone breakdown the API call into RESTClient & RESTRequest properties for me?
I've been wrestling with this for hours and no success so far.
Below is a simple example of the assignment of properties for the REST components.
Creating a new project and dropping a Button, RESTClient, RESTRequest, RESTResponse, and Memo on the form - you can use the code below on your Button Click event to see it work.
procedure TForm1.Button1Click(Sender: TObject);
begin
RESTRequest1.Client := RESTClient1;
RESTRequest1.Response := RESTResponse1;
RESTClient1.BaseURL := 'https://api.hubapi.com';
RESTRequest1.Resource :=
'contacts/v1/lists/all/contacts/all?hapikey=Demo&count=1000';
RESTRequest1.Execute;
Memo1.Text := RESTResponse1.Content;
end;
Related
I'm working on a project in Delphi 10.1 Berlin which integrates with GitHub. This project intends to download repositories via ZIP files. However, I'm facing some issues.
Originally, I chose (as always) to use Indy to integrate with the GitHub API. I've always used Indy for all web API consumption. However, I'm not having any success using it with GitHub.
The API requires HTTPS. I have obtained the latest OpenSSL DLLs for use with Indy, and am using the Indy library with Delphi 10.1 Berlin.
I have setup a TIdHTTP component with a TIdSSLIOHandlerSocketOpenSSL attached. I've set that IO Handler to all the Method options available, and not one gives me a valid response. I get one of two different responses...
When using sslvSSLv3, I get: error:14094410:SSL routines: SSL3_READ_BYTES:sslv3 alert handshake failure.
When using sslvTLSv1_2, I get: error:1409442E:SSL routines:SSL_READ_BYTES:tlsv1 alert protocol version
I had to resort to TRESTClient for now just to be able to work with the API. But it doesn't handle binary properly.
The test is as simple as https://api.github.com. I can call that in Chrome and Postman, and get a response. Just not via Indy.
How can I accomplish a connection with GitHub's API via Delphi's Indy library?
This Indy HTTP subclass works with the GitHub API.
type
TIndyHttpTransport = class(TIdCustomHTTP)
public
constructor Create;
end;
implementation
uses
IdSSLOpenSSL;
{ TIndyHttpTransport }
constructor TIndyHttpTransport.Create;
var
SSLIO: TIdSSLIOHandlerSocketOpenSSL;
begin
inherited Create;
HTTPOptions := HTTPOptions + [hoNoProtocolErrorException, hoWantProtocolErrorContent];
SSLIO := TIdSSLIOHandlerSocketOpenSSL.Create(Self);
SSLIO.SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
SSLIO.SSLOptions.Mode := sslmClient;
SSLIO.SSLOptions.VerifyMode := [];
SSLIO.SSLOptions.VerifyDepth := 0;
Self.IOHandler := SSLIO;
// Request.UserAgent := 'my useragent string';
end;
Maybe your code also needs to modify the user agent string (because I use this code with different service providers, not only GitHub. Some of them require a modified user agent string instead of the default).
Source: https://github.com/michaelJustin/daraja-framework/blob/master/demo/common/IndyHttpTransport.pas
If I authenticate to D365 via the web browser, and then enter the following URL:
https://mytenantcode.crmserver.dynamics.com/api/data/v8.2/systemusers?$select=systemuserid,lastname,firstname,title&$top=3
I can get back the top 3 records with the data I requested.
I seem to be able to authenticate to D365 in code as per my other question (which I answered), and have an access token but I cannot seem to be able to determine how to setup the TRESTRequest object so that the Execute works.
Currently, it always returns a 401 Unauthorized error.
I've tried setting the TOAuth2Authenticator.AccessToken property to the token I received from D365, and then set the TRESTClient.Authenticator property to the TOAuth2Authenticator and the TRESTQuest.Client to the TRESTClient, which is how the examples work in the RESTDemos project, but I still get 401.
This is the last example of the code I tried, that should have worked, given that all the REST objects are linked correctly:
RESTClient.BaseURL := 'https://**mytenantcode**.**crmserver**.dynamics.com/api/data/v8.2/';
RESTRequest.Method := TRESTRequestMethod.rmGET;
RESTRequest.Resource := 'systemusers?$select={SELECT}&$top={TOP}';
RESTRequest.AddParameter('SELECT', 'systemuserid,'+
'lastname,'+
'firstname,'+
'title');
RESTRequest.AddParameter('TOP', '3');
RESTRequest.Execute;
I finally got it to return the correct information using the following code for calling the Web API:
RESTClient.BaseURL := 'https://mytenantcode.crmserver.dynamics.com/';
RESTRequest.Resource := 'api/data/v8.2/systemusers?$select=int_staffnumber,'+
'_int_serviceareaid_value,'+
'_territoryid_value,'+
'lastname,'+
'firstname,'+
'systemuserid,'+
'title';
RESTRequest.AddAuthParameter('Authorization', 'Bearer ' + AToken, TRESTRequestParameterKind.pkHTTPHEADER,
[TRESTRequestParameterOption.poDoNotEncode]);
RESTRequest.Execute;
The important change was the addition of the Authorization header parameter, and not using the Params for the query parameters as it seems the REST Client Library doesn't actually do it correctly.
Also had to change the ResourceURI for the token authorization to match the https://mytenantcode.crmserver.dynamics.com URL being used for the method call.
I'm working on a DElphi FMX project where I make a lot of requests to a REST backend.
I'm using one TRESTClient, and are dynamically creting a TRESTRequest every time I ask for something, my plan is to make it multitreading to make the UI be more responsive.
I have made a function called DoRequest, that do the actual request, it looks like something this:
Function TFormMain.Dorequest(Meth:TRESTRequestmethod;Url,RequestBody:String;
Var Respons: TCustomRESTResponse):Boolean;
Var
par: TRESTRequestParameter;
Req : TRESTRequest;
begin
Req := TRESTRequest.Create(RESTClient);
With Req do
try
if RequestBody<>'' then
begin
Params.Clear;
par := Params.AddItem('body',RequestBody);
par.ContentType := ctAPPLICATION_JSON;
par.Kind := pkREQUESTBODY;
end;
Method := Meth;
Resource := Url;
Execute;
Respons := Response;
Result := Respons.StatusCode In [200,201];
finally
Req.Free; // <-Error here
end;
end;
I call it like this:
procedure TFormUser.Button1Click(Sender: TObject);
Var
Respons: TCustomRESTResponse;
begin
If DoRequest(rmPOST,CreateUserUrl,JSON,Respons) then
begin
ShowMessage('User '+EdEmail.Text+' created');
ModalResult := MrOk;
end
However, I get an Acces Violation when freeing Req, my TRESTRequest.
I found out that it is because the TCustomRESTResponse Respons is just made a pointer to the memory where the Req.Response is placed, so freeing Req also destroys Respons.
My question is: How do I make a copy of Req.Response that lives after Req is freed?
I have tried Respons.Assign(Response), but it gives the rather strange error: "Cannot assign a TCustomRESTResponse to a TFormMain"
Am I doing this the wrong way, also keeping in mind that I would like the actual request to be in another tread?
Michael
When you don't link your own TRESTResponse to the client, the client will create one of its own and also free it. If you create your own TRESTResponse and assign it, the client will leave it alone, and you can free it whenever you want.
That said, like I mentioned in the comment, I think it's probably better to let the thread deal with deserializing the response, and have it pass a more generic class or record holding the relevant information (a value object, if you're into that), rather than passing around the specific TRESTResponse.
Well, I'm developing a REST Client application that needs to send a POST request using application/x-www-form-urlencoded as Content type. I'm using Delphi's default REST.Client components. I need to send data in XML format, like the following example:
data=<serviceLocal>
<description>Francisco Hansen</description>
<active>true</active>
<corporateName>Francisco Hansen</corporateName>
<country>Brasil</country>
<state>PR</state>
<city>Pato Branco</city>
<cityNeighborhood>Centro</cityNeighborhood>
<streetType>Rua</streetType>
<street>Tocantins</street>
<streetNumber>2334</streetNumber>
<streetComplement>Ap101</streetComplement>
<zipCode>85501-272</zipCode>
<cellphoneStd>46</cellphoneStd>
<cellphoneNumber>99999999</cellphoneNumber>
<phoneStd>46</phoneStd>
<phoneNumber>99999999</phoneNumber>
</serviceLocal>
How can I add all these as POST parameters to a TRestRequest and then send this request using a TRestClient?
Using a Rest.Client.TRESTRequest component, I've been able to set the POST parameters for the request. I've named the TRESTRequest as rqst1
.
rqst1.Method := rmPost;
rqst1.Params.AddItem; //Adds a new Parameter Item
rqst1.Params.Items[0].name := 'data'; //sets the name of the parameter. In this case, since i need to use 'data=' on the request, the parameter name is data.
rqst1.Params.Items[0].Value := params; //Adds the value of the parameter, in this case, the XML data.
rqst1.Params.Items[0].ContentType := ctAPPLICATION_X_WWW_FORM_URLENCODED; //sets the content type.
rqst1.Params.Items[0].Kind := pkGETorPOST; //sets the kind of request that will be executed.
I am using Go for soap web service.
When I call the webservice I do like this.
request := fmt.Sprintf(para)
cli := new(http.Client)
//http.Header["http://webservice.ei"]="notify"
resp, err := cli.Post("http://127.0.0.1:8751/WebRoot/services/SecurtyWebService/notify?wsdl&targetNamespace=http://webservice.ei","text/xml;charset=utf-8",bytes.NewBufferString(request))
I get this error.
<faultstring>namespace mismatch require http://webservice.ei found none</faultstring>
I learn that the server require a targetNameSpace para. I also know that in java. People fix this by using:
QName opAddEntry = new QName("http://webservice.ei", "notify");
But I find there's no way for me to add this parameter.
Can anyone gime me some advice on how to set the namespace when calling the soap webservice in go?