multi level parameters to rest post - ruby

How do I pass multilevel parameters to POST when I'm using net/http library?
example that works:
require "net/http"
http = Net::HTTP.new("localhost", 3000)
request = Net::HTTP::Post.new("/external/rd")
request.set_form_data({:name => 'device_rb'})
response = http.request(request)
puts response.body
but common rails notation would be:
"device" => {:name => 'device_rb'}
I have no idea how to put this embeded parameters to set_form_data method. Any help?
Regards

If you are posting form data, your data will get encoded in x-www-form-urlencoded format. This is more or less a simple key/value format with no nesting of structures.
If you want nesting for the data you pass to the server, you would have to use a format that allows it, such as JSON or XML. You cannot set the payloads for these formats with set_form_data though.
You rather set them using request.body = payload. See also this simple example for posting a JSON payload.

Related

Pass parameters in RestClient post request

I want to send parameters with a POST request using the RestClient gem (but I don't want to pass the params as JSON).
In a GET request, I would have:
url = "http://example.com?param1=foo&param2=bar"
RestClient.get url
How can I pass the same params but in a POST request without passing a JSON ?
Read ReadMe file of Rest-client git, it has lots of examples showing different types of request.
For your answer, try :
url = "http://example.com"
RestClient.post url,:param1=>foo, :param2=>bar

Find what my Query's POST data is?

This is what I am having trouble understanding and doing.
I need to add a header called sign with the query's POST data signed by my key's "secret" according to the HMAC-SHA512 method. What is my query's post data? And how can I find it so that I can encrypt it and send it as a header.
These are my parameters: "command" => "returnBalances", "nonce" => Time.now.to_i
Please let me know:
How do I find my post request data.
How do I use the HMAC-SHA512 method to encrypt this data so that I can send it in a header. (using Ruby)
Thank you people let me know.
I answered your question more completely here, in the context of the Poloniex exchange:
Ruby Http Post Parameters
To answer your specific questions from this post:
How do I find my post request data?
POST data simply means the body of your request. This could be JSON, plain text, form data, etc. In cases where a specific format (i.e. JSON) isn't mentioned, POST data probably refers to POST form data (Content-Type: application/x-www-form-urlencoded). This is how data submitted from a web form is formatted and indeed that appears to be what Poloniex is looking for.
x-www-form-urlencoded data can be produced like this in Ruby:
form_data = URI.encode_www_form({:command => 'returnBalances', :nonce => Time.now.to_i * 1000 })
puts form_data
command=returnBalances&nonce=1447537613000
Mozilla Developer's Network link on POST form data.
How do I use the HMAC-SHA512 method to encrypt this data so that I can send it in a header? (using Ruby)
HMAC digest produces a unique string based on a secret key and the data provided. In Ruby, you can produce an HMAC digest like so:
OpenSSL::HMAC.hexdigest( 'sha512', secret, form_data)

To 406 or not to 406 (http status code)

I'm developing a RESTful web application in Ruby with Sinatra. It should support CRUD operations, and to respond to Read requests I have the following function that formats the data according to what the request specified:
def handleResponse(data, haml_path, haml_locals)
case true
when request.accept.include?("application/json") #JSON requested
return data.to_json
when request.accept.include?("text/html") #HTML requested
return haml(haml_path.to_sym, :locals => haml_locals, :layout => !request.xhr?)
else # Unknown/unsupported type requested
return 406 # Not acceptable
end
end
Only I don't know what is best to do in the else statement. The main problem is that browsers and jQuery AJAX will accept */*, so technically a 406 error is not really the best idea. But: what do I send? I could do data.to_s which is meaningless. I could send what HAML returns, but they didn't ask for text/html and I would rather notify them of that somehow.
Secondly, supposing the 406 code is the right way to go, how do I format the response to be valid according to the W3 spec?
Unless it was a HEAD request, the response SHOULD include an entity containing a list of available entity characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. Depending upon the format and the capabilities of the user agent, selection of the most appropriate choice MAY be performed automatically. However, this specification does not define any standard for such automatic selection.
It looks like you're trying to do a clearing-house method for all the data types you could return, but that can be confusing for the user of the API. Instead, they should know that a particular URL will always return the same data type.
For my in-house REST APIs, I create certain URLs that return HTML for documentation, and others that return JSON for data. If the user crosses the streams, they'll do it during their development phase and they'll get some data they didn't expect and will fix it.
If I had to use something like you're writing, and they can't handle 'application/json' and can't handle 'text/html', I'd return 'text/plain' and send data.to_s and let them sort out the mess. JSON and HTML are pretty well established standards now.
Here's the doc for Setting Sinatra response headers.

How to read POST data in rack request

When I run the curl command
curl -v -H "Content-type: application/json" -X POST -d '{"name":"abc", "id":"12", "subject":"my subject"}' http://localhost:9292
to send a POST request with data to my Rack application, my code prints out {}. That is coming from puts req.POST() in the code below.
Why does it print out {} instead of the POST data? And how do I correctly access the POST data in my Rack application?
require 'json'
class Greeter
def call(env)
req = Rack::Request.new(env)
if req.post?
puts req.POST()
end
[200, {"Content-Type" => "application/json"}, [{x:"Hello World!"}.to_json]]
end
end
run Greeter.new
From reading the docs for POST, looks like it is giving you parsed data based on other content types. If you want to process "application/json", you probably need to
JSON.parse( req.body.read )
instead. To check this, try
puts req.body.read
where you currently have puts req.POST.
req.body is an I/O object, not a string. See the body documentation and view the source. You can see that this is in fact the same as mudasobwa's answer.
Note that other code in a Rack application may expect to read the same I/O, such as the param parsers in Sinatra or Rails. To ensure that they see the same data and not get an error, you may want to call req.body.rewind, possibly both before and after reading the request body in your code. However, if you are in such a situation, you might instead consider whether your framework has options to process JSON directly via some option on the controller or request content-type handler declaration etc - most likely there will be an option to handle this kind of request within the framework.
Try:
env['rack.input'].read
I found it in "How to receive a JSON object with Rack" and, though it still sounds weird to me, it likely works.
You can try:
req.params
Hope this can help you.

RestClient multipart upload from IO

I am trying to upload data as multipart using RestClient like so:
response = RestClient.post(url, io, {
:cookies => {
'JSESSIONID' => #sessionid
},
:multipart => true,
:content_type => 'multipart/form-data'
})
The io argument is a StringIO that contains my file, so it's from memory instead of from the disk.
The server (Tomcat servlet) is unable to read the multipart data, giving an error:
org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
So I believe that RestClient is not sending it in multipart format? Anyone see the problem? I am assuming the problem is on the Ruby (client) side, but I can post my servlet (Spring) code if anyone thinks it might be a server-side problem.
I also wonder what RestClient would use for the uploaded filename, since there isn't an actual file... Can you have a multipart request without a filename?
You can do this, it simply requires subclassing StringIO and adding a non-nil path method to it:
class MailIO < StringIO
def path
'message'
end
end
I've just checked this, and the Mailgun api is pretty down with this.
After consulting with the author of the rest-client library (Archiloque), it seems that if this is possible, the API is not set up to handle it easily. Using the :multipart => true parameter will cause the IO to be treated like a file, and it looks for a non-nil #path on the IO, which for a StringIO is always nil.
If anyone needs this in the future, you'll need to consult with the library's mailing list (code#archiloque.net), as the author seems to think it is possible but perhaps not straightforward.
It CAN easily do streaming uploads from an IO as long as it's not multipart format, which is what I ended up settling for.

Resources