Sending an array of string in a request made with rest-client gem - ruby

I am creating a gem to implement the Calendly API and I need to make a request like
curl --header "X-TOKEN: <your_token>"
--data "url=https://blah.foo/bar&events[]=invitee.created"
https://calendly.com/api/v1/hooks
to create a webhook.
As you may see, events is passed as an array of strings and this is indicated by the [].
I am trying to use RestClient::Request#execute to send this request, but I don't know how to pass this array of strings in this case.
I tried
RestClient::Request.execute(method: :post,
url: #uri,
params: { url: url,
events: "invitee.#{type}"
},
headers: { "X-TOKEN": "#{#api_key}" })
but then I am not sending an array as the API expects.
I also tried
RestClient::Request.execute(method: :post,
url: #uri,
params: { url: url,
'events[]': "invitee.#{type}" },
headers: { "X-TOKEN": "#{#api_key}" })
but it didn't work either. I got a bad request error and nothing else.
How should I build my request in this case?

Posted for visibility (previously answered in comment)
RestClient will appropriately serialize a native ruby Array for you meaning
events: ["invitee.#{type}"]
will be serialized into events[]=invitee.created where type == 'created'. This will work for an Array with multiple values too.
events: ["more","than","one"]
will be converted to events[]=more&events[]=than&events[]=one.
Finally it also handles an other data types inside an Array such as another Hash
events: [{first_name: 'Zaphod', last_name: 'Beeblebrox'}]
will become events[][first_name]=Zaphod&events[][last_name]=Beeblebrox

Related

In Cypress, how do I stub a POST API request with parameters in the body?

I am writing an end-to-end test with Cypress and I would like to stub the network requests which my application makes. Specifically, I would like to stub out multiple POST requests which have parameters in the body and to change my simulated response based on those parameters.
I would like to do something like
cy.route({
method: "POST",
url: "/todos/add"
params: {
"urgency": 3,
"stakeholder_id": "SKH001"
},
response: "fixture:add1.json",
})
cy.route({
method: "POST",
url: "/todos/add"
params: {
"urgency": 1,
},
response: "fixture:add2.json",
})
But after reading through
https://docs.cypress.io/guides/guides/network-requests.html and https://docs.cypress.io/api/commands/route.html#Arguments, I do not see a supported way of checking the arguments in the request being stubbed.
Can I accomplish this by passing a function to the onRequest parameter of cy.route? If so, what would I return from that function which tells cypress "this route actually does not handle this request"?
cy.route({
method: "POST",
url: "/todos/add"
body: {
"urgency": 1,
},
response: "fixture:add2.json",
})
One option is to use Mirage.js
https://miragejs.com/docs/comparison-with-other-tools/#cypress-route-mocks
See their tutorial: https://miragejs.com/quickstarts/cypress/
You can use intercept method too.
cy.intercept('POST', <your api end point>, {response:
<your json file path>}).as('postAPI')
If your Cypress version is greater than 6, you should refactor to use intercept. Intercept handles params really cleanly and you can assign parts of output to a file using the alias or in the callback.
https://docs.cypress.io/api/commands/route
https://docs.cypress.io/api/commands/intercept#Arguments

Axios AJAX call nulls parameter

I use Vuejs to create my frontend for my project.
At the creation of one component ('TimeCapsy.vue'), I make an AJAX call to my backend like this:
created: function () {
if (verify.verify_login()) {
let token = this.$cookies.get('jwt_us_cas');
let params = {'jwt': token};
console.log(params);
axios({
method: 'post',
url: dev.HOST+'getuserinfoobject',
params: queryString.stringify(params)
})
.then(response => {
console.log(response.data)
})
}
}
As you can see I use the
this.$cookies.get('jwt_us_cas');
to get the a json web token, that I set on the client at the login.
I use the queryString Library to stringify my parameters for my request.
I also tried it without the queryString.stringify(params) call, but I get the same error, e.g. the parameter still turns into null.
When I look at the console log, where I check the params variable, I get this output:
{jwt: "my token comes here"}
So I can see, that it gets the correct value from the cookie.
But when I check the answer from my backend (PHP), I get this error:
Undefined index: jwt in <b>D:\casb\public\index.php</b> on line <b>52</b>
Of course I know that it means, that jwt is null, but I can't understand why.
As I said, right before I make the call I check the params and it shows the token.
I checked the endpoint with Postman and the token as the jwt parameter and it returned a successfull call with the correct answer.
A correct answer is basically just a nested object with some information in it.
My PHP endpoint is pretty basic too:
Router::add('/getuserinfoobject', function () {
$response['response'] = User::getUserInfoObject($_POST['jwt']);
echo json_encode($response);
}, 'post');
So I guess that right before or in my call it nulls my parameter. But I can't understand how, since I make a lot of requests and never had this problem.
From axios docs
params are the URL parameters to be sent with the request
Which means, you should get the value with PHP $_GET.
Or $_REQUEST (which stores both $_GET, $_POST. Also $_COOKIE).
The other hand, you can use data key as docs says
data is the data to be sent as the request body
Only applicable for request methods PUT, POST, and PATCH
So the value would be available in $_POST
axios({
method: 'post',
url: dev.HOST+'getuserinfoobject',
data: {
jwt: token
}
})

Calling public class method within string

I am trying to insert a public class method within the payload of a POST call. The code I've written:
RestClient::Request.execute(method: :post,
url: $url,
payload: '{"event" : "start_skill",
"uuid" : "RandomSecure.uuid"}',
headers: {"Content-Type" => "application/json"})
So what I am trying to do is for this call to generate a new UUID each time the call is made. The problem, obviously, is the fact that the entire payload is in single quotation marks (e.g. ' ). I've tried wrapping the UUID in single quotation marks, but that does not generate the same output. I've also tried #{, but that does not work either.
What else could I try for the UUID method to be called upon without changing the message?
There are a couple of ways you could go. You could use an interpolated string (string with double quotes "like this", and indeed use #{} within this string. However, you would need to manually escape every single " in your string which can become hassle.
The other method would be to make a hash with your desired json data, and call .to_json on it.(note: you need to add require 'json'.
{ event: "start_skill", uuid: RandomSecure.uuid }.to_json
Which would result in:
"{\"event\":\"start_skill\", \"udid\": \"some random udid\"}"
So to wrap it up:
# somewhere at the top of your file
require 'json'
payload = { event: "start_skill", uuid: RandomSecure.uuid }.to_json
RestClient::Request.execute(method: :post,
url: $url,
payload: payload,
headers: { "Content-Type" => "application/json" })

sendAJAX data parameter in CasperJs

again, I got another problem with casperjs, now with sendAJAX function.
It says that sendAJAX has 5 parameters which are these followings :
url: The url to request.
method: The HTTP method (default: GET).
data: Request parameters (default: null).
async: Flag for an asynchroneous request? (default: false)
settings: Other settings when perform the AJAX request (default:
null)
So, it says the data method is object so, it should be filled with :
var data = new Object();
data.amount= 15;
and also with this one,
var data = {amount:15};
but there were no successful value send to my web service (always send 0 as value, but ajax request successful, even returning the json data) which has an url like this
"http://localhost:9000/TempCountryAmountREST/setCountryAmount"
It will be succeed if I direct bind my data variable to my url like this :
"http://localhost:9000/TempCountryAmountREST/setCountryAmount?amount="+amount
[UPDATE]
The TempCountryAmountREST is my controller name and setCountryAmount is my function inside my controller.
[UPDATE]
I forgot to include my usage of sendAJAX(), here is the code that I use :
return JSON.parse(__utils__.sendAJAX(wsurl, "POST" , data, false, { contentType: "application/json" }));
So how does I fill the data in the sendAJAX parameter?
Thanks in advance...
Sorry, I've found what the answer is.
I make some mistakes in contentType which I was set with contentType: "application/json" instead of contentType: "application/x-www-form-urlencoded" }
If we are looking about how ajax send the content from method send(), they were use x-www-form-urlencoded. See this for more detail
When we see through casperjs clientutils.js script, we should found how sendAJAX work.
On the `this.sendAJAX = function sendAJAX(url, method, data, async, settings) {
}
there are url construction logic which transformed our Object (if so) to x-www-form-urlencoded form. So that we need to set our contentType as application/x-www-form-urlencoded
Very well, thanks for your attention...

How can I return a response to an AngularJS $http POST to Sinatra?

I am able to successfully POST from AngularJS to my Sinatra route such that I get a "200" Status.
When I inspect in Chrome, I see the request payload as follows:
{"input":"testing"}
But response is empty.
Here is how I am POST-ing:
$http({
method: "POST",
url: "http://floating-beyond-3787.herokuapp.com/angular",
/*url: "https://worker-aws-us-east-1.iron.io/2/projects/542c8609827e3f0005000123/tasks/webhook?code_name=botweb&oauth=LOo5Nc0x0e2GJ838_nbKoheXqM0",*/
data: {input: $scope.newChat}
})
.success(function (data)
{
// $scope.chats.push(data);
$scope.chats.push($scope.newChat)
// if successful then get the value from the cache?
})
.error(function (data)
{
$scope.errors.push(data);
});
};
$scope.newChat = null
Chrome under Request Payload shows it properly -- as above.
When I check the logs in Heroku where I run my Sinatra app, I can't tell if I am properly processing the request payload. And I'm definitely not getting anything in the Response:
post '/angular' do
puts "params: #{params}"
puts params[:input]
puts #json = JSON.parse(request.body.read)
return RestClient.post 'https://worker.io' {:send => params[:input]}
end
My expectation is:
The Sinatra app can receive the payload :input
It can successfully post to my worker on iron.io
It can return something back in the Response to Angular JS along with Success.
Is this possible and if so, how?
Possibly you are running into a case where the request.body has already been read further up the chain before hitting your route.
Try the following
request.body.rewind
request_payload = JSON.parse request.body.read
This is a fairly common issue encountered in Sinatra so if this addresses your issue you may want to put it in a before filter.
before do
request.body.rewind
#request_payload = JSON.parse request.body.read
end
Also the following will not work with a JSON payload.
params[:input]
The params[:field] style works if the Content-Type is application/x-www-form-urlencoded to allow accessing form data in a traditional web application style. It also works to pull params off a parameterized route; something like the following.
post '/angular/:data'
puts params[:data]
# Do whatever processing you need in here
# assume you created a no_errors var to track problems with the
# post
if no_errors
body(json({key: val, key2: val2, keyetc: valetc}))
status 200
else
body(({oh_snap: "An error has occurred!"}).to_json) # json(hash) or hash.to_json should both work here.
status 400 # Replace with your appropriate 4XX error here...
end
end
Something I did recently was to use this last style post 'myroute/:myparam and then Base64 encode a JSON payload on the client side and send it in the URL :myparam slot. This is a bit of a hack and is not something I would recommend as a general practice. I had a client application that could not properly encode the JSON data + headers into the request body; so this was a viable workaround.

Resources