Delphi RESTClient POST request - rest

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.

Related

How to call the Dynamics 365 OData endpoint to get a list of users from Delphi

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.

How to access invoke response object variable in following steps of assembly

the assembly of my API Connect API contains two invokes. The first is calling an internal routing API to get some routing information. The response of this routing API should not be passed to the second invoke.
If I do not configure a 'response object variable' in the invoke of the routing API, the original request body is overwritten and the second API gets the result from the routing API as request body. And if I specify a 'response object variable' in the routing invoke, I can not access the content (json) of this variable in the following steps.
How can I solve this issue?
Thx 4 help.
Rather than relying on reading the request object, you can read from your configured 'response object variable' later on in the flow. For instance, if your first invoke has a response object variable set to 'resp1', you can access the JSON payload using '$(resp1.body)' later on in the flow. Using this technique will allow you to store the response of each invoke in a separate object, avoiding the overwriting issue. These response object variables can be read just like any other context variable in the flow.
For more info, check out these links in the Knowledge Center:
Invoke Policy: https://www.ibm.com/support/knowledgecenter/en/SSMNED_5.0.0/com.ibm.apic.toolkit.doc/rapim_ref_ootb_policyinvoke.html
Context Variables:
https://www.ibm.com/support/knowledgecenter/SSMNED_5.0.0/com.ibm.apic.toolkit.doc/capim_context_references.html
I don't understand this part:
[...] "And if I specify a 'response object variable' in the routing
invoke, I can not access the content (json) of this variable in the
following steps." [...]
Why can't you access the content of this variable in the following steps?
Save copy of the request...
... that you received. What I'd do is always save a copy of the data received in the invoke to a processed variable instead of the (raw) original request.
In your GatewayScript try something like this:
let objRequest = apim.getvariable("request");
let body = null;
Here I recommend you to change the body (if json) to a standard js object
if(objRequest && objRequest.hasOwnProperty("body")){
try{
body = JSON.parse(objRequest.body);
}catch(e){
body = objRequest.body;
}
}
Remember to stringify the complete object before saving it as global variable. Is the only way to store it (because you can only store a string value in this kind of variables)
apim.setvariable("objRequest", JSON.stringify(objRequest));
Retrieve copy of the request...
...that you have saved in global variables you can get it from any other GatewayScript that you want this way:
let objRequest = JSON.parse(apim.getvariable("objRequest"));
Be careful not to assign an existent name to the apim.setvariable(name, value) because if you use "request" as name instead of "objRequest" (or other), you'll be replacing the original request element, and we don't want that to happen.
If you need to set or retrieve the status.code...
...you can do it with:
let statusCode = objRequest.body.status.code;

Invalid_request_parameter (create and sending envelopes)

I'm trying to use a service of DocuSign API in an abap project. I want to send a document to a specific email so it can be signed. But im getting the following error:
"errorCode": "INVALID_REQUEST_PARAMETER",## "message": "The request contained at least one invalid parameter. Query parameter 'from_date' must be set to a valid DateTime, or 'envelope_ids' or 'transaction_ids' must be specified.
I tried the following:
CALL METHOD cl_http_client=>create_by_url
EXPORTING
url = l_url (https://demo.docusign.net/restapi/v2/accounts/XXXXXX')
proxy_host = co_proxy_host
proxy_service = co_proxy_service
IMPORTING
client = lo_http_client
lo_http_client->request->set_method( method = 'POST').
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'Accept'
value = 'application/json'.
CALL METHOD lo_http_client->request->set_header_field
EXPORTING
name = 'X-DocuSign-Authentication'
value = get_auth_header( ). (json auth header)
CALL METHOD lo_http_client->request->set_cdata
EXPORTING
data = create_body( ).
This is my body:
CONCATENATE
`{`
`"emailSubject": "DocuSign REST API Quickstart Sample",`
`"emailBlurb": "Shows how to create and send an envelope from a document.",`
`"recipients": {`
`"signers": [{`
`"email": "test#email",`
`"name": "test",`
`"recipientId": "1",`
`"routingOrder": "1"`
`}]`
`},`
`"documents": [{`
`"documentId": "1",`
`"name": "test.pdf",`
`"documentBase64":` `"` l_encoded_doc `"`
`}],`
`"status": "sent"`
`}` INTO re_data.
The api request to get the Baseurl is working fine. (I know the error is quite specific what the problem is, but i cant find any sources on the docusign api documentation that one of the mentioned parameters should be added to the request)
Thank you in regards
The error message seems to indicate that you're Posting to an endpoint that requires certain query string parameters -- but you're not specifying them as expected in the query string. I'd suggest you check the DocuSign API documentation for the operation you are using, to determine what query string parameters it requires, and then ensure that you're including those parameters in your request URL.
If you can't figure this out using the documentation, then I'd suggest that you update your post to clarify exactly what URL (endpoint) you are using for the request, including any querystring parameters you're specifying in the URL. You can put fake values for things like Account ID, of course -- we just need to see the endpoint you are calling, and what qs params you're sending.
To create an envelope, use
https://demo.docusign.net/restapi/v2/accounts/XXXXXX/envelopes
instead of
https://demo.docusign.net/restapi/v2/accounts/XXXXXX
Thank you for all the answers, i found the mistake. Creating the request wasn´t the problem. I was using the wrong "sending"-method -_-.
now its working :)
lo_rest_client->post( EXPORTING io_entity = lo_request_entity ).

How do I add a field for a header for an authentication token for Swagger UI?

My team has just started creating RESTful services for data that has previously been handled by a large monolithic legacy application. We want to document the api with Swagger UI and I have set up with one problem.
I need to pass a SAML token as a header parameter, otherwise when we try to click on the "Try it out!" button I get a 401 Authentication error. How do I add a field to the Swagger UI so that someone can put a String for a SAML token to be sent in the request?
This is actually really easy. I saw references to the answer in the documentation but I didn't really understand what it was saying. There is a field at the top next to where your service URL goes and you can use that field to input a string to pass as a header value. That input field has an id of #input_apiKey.
Then in the index.html file you just add a line to the addApiKeyAuthorization() javascript function telling it to take the value of that field and pass it as whatever value you need.
Example:
function addApiKeyAuthorization(){
var key = $('#input_apiKey')[0].value;
if(key && key.trim() != "") {
swaggerUi.api.clientAuthorizations.add("samlToken", new SwaggerClient.ApiKeyAuthorization("samlToken", key, "header"));
swaggerUi.api.clientAuthorizations.add("Content-Type", new SwaggerClient.ApiKeyAuthorization("Content-Type", "application/json", "header"));
swaggerUi.api.clientAuthorizations.add("Accept", new SwaggerClient.ApiKeyAuthorization("Accept", "application/json", "header"));
}
}
$('#input_apiKey').change(addApiKeyAuthorization);
This sets the Content-Type and Accept headers to the same values for every request, and takes the value in that input field at the top of the page in the green header and sets it as my SAML token. So now if I paste in a valid SAML string my request works and I get data back!

Web API calls with RestSharp - prepends application/json to body causing null parameter on action

I have a Web API service that I'm trying to access via the console using RestSharp. My RestSharp code looks like this:
RestClient client = new RestClient(baseUrlString);
RestRequest request = new RestRequest("controllername/actionname");
request.RequestFormat = DataFormat.Json;
ProcessQuestion model = new ProcessQuestion()
{
Id = "123456",
InstanceId = "123",
UniqueId = "bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626",
PostedAnswer = new Dictionary<string, string>() { { "question_7907_1", "selected" }, { "question_7907_2", "selected" } }
};
request.AddBody(model);
var response = client.Execute(request)
My Web API action takes a model that has the same parameters as the above model. When the call executes, the binding fails and the parameter is null. I suspect this is due to the RestRequest.AddBody method prepending application/json to the body value as shown below:
{application/json={"Id":"123456","InstanceId":"123","UniqueId":"bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626","PostedAnswer":{"question_7907_1":"selected","question_7907_2":"selected"}}}
If I post using Fiddler the body binds to the model properly. Below is the body value I provided in Fiddler:
{'Id':'123456','InstanceId':'123','Uniqueid':'bfb16a18-d0d6-46ab-a5b3-2f0ebbfe8626','PostedAnswer':{'question_7907_1':'selected','question_7907_2':'selected'}}
Note that the body value in fiddler is the same with the exception of prepending the application/json key.
Also to note: I've tried what seems like everything...I've separated the parameters out in the action, used FromBody and FromUri attributes, tried custom DictionaryModelBinder's, tried custom ValueBinders, tried changing the way I'm using RestSharp (AddParameter with a RequestBody parameter, AddObject, different URL styles, etc.).
Has anyone else encountered this, and if so, did you solve it? I chose Web API for this service with hopes the model binding would work as it does in MVC, but I'm seeing that isn't the case.
Thanks
EDIT (resolved):
RestSharp automatically uses the JsonSerializer for objects passed in the AddBody method. I figured I was missing something simple, and indeed I was... Adding the Method.Post parameter to the RestRequest instantiation solved the problem.
Specify the method when creating the request:
RestRequest request = new RestRequest("controllername/actionname", Method.POST);
Not sure what the default serializer is for body - you can try making it explicit:
request.AddBody(request.JsonSerializer.Serialize(model));
I'm not sure where the 'application/json' is coming from - that's the Content-Type header you should be sending with your request, definitely not part of the body. So do this instead:
request.AddHeader("Content-type", "application/json; charset=utf-8");
If this doesn't help, try making your code as similar to the example on their site as possible. Try removing complexity (even if it means changing the required functionality) - get it to a point when it works and build additional functionality on that.
http://restsharp.org/