How to get xml post request parameters in Sinatra? - ruby

I have a very simple Sinatra app which only does log out the params in the action, and then I use curl to send post data in xml format, but sinatra didn't get the xml parsed:
echo '<something>tyrael tong</something>' | curl -X POST -H 'Content-Type: text/xml' -d #- http://localhost:9528/status/update
I searched through google with no solution to this. Am I suppose to parse the xml post data by myself?

try this code
require 'plist'
post 'some/route'
content_type :xml
value=Plist::parse_xml(request.body)
end

Find a rack parser: https://github.com/achiu/rack-parser which could do the job I want: parse the post body into parameter.
P.S. And need to set the content type to "application/xml"

Yes, content type is just a hint for a server how to handle it. If your server can receive say XML or JSON, content type can tell you how to parse it.

As the body of your post message is an xml it will not be parsed by either rails/sinatra. If you want parsing to be done you will need to change the format of data that you are sending and set the content type to "application/x-www-form-urlencoded". Then Sinatra will parse that data and put it into the params hash.

Related

Accept file upload (without a form) in Sinatra

I have this Sinatra::Base code:
class Crush < Sinatra::Base
post '/upload' do
erb params.inspect
end
end
I am using Postman and its interface for uploading a file. So I send a POST request with form-data, where in the body of the request the name is hello and the value is a file test.txt which contains just a simple string hey there.
When I do params.inspect I get this long string
{"------WebKitFormBoundaryocOEEr26iZGSe75n\r\nContent-Disposition: form-data; name"=>"\"hello\"; filename=\"test.txt\"\r\nContent-Type: text/plain\r\n\r\nhey there\r\n------WebKitFormBoundaryocOEEr26iZGSe75n--\r\n"}
So basically a long has with a single key and a single value. Reading most Sinatra tutorials (where the file is accepted from a form), there's a nice way Sinatra handles this using params[:file], but this doesn't seem to be the case when the file is coming straight from the body of an HTTP request.
I tried a non-modular approach too withou Sinatra::Base, thinking it's some parsing middle-ware missing, but got the same result.
Is there something I'm missing here? Must I go and make my own custom parser to get the content of this long hash? Or is there an easier way?
I figured it's Postman issue. When I switch from 'x-www-form-urlencoded' to 'form-data' in Postman, in the Header section, the field: Content-Type => application/x-www-form-urlencoded is NOT removed. So for those who encounter this problem, make sure you remove it manually.

Retrieve POST response data with cURL

In jQuery/AJAX you can make POST requests and get their response with something like
$.post(url, data, function(res){
//do something
});
Where res contains the server's response. I am trying to replicate this with cURL in bash.
curl -d "data=data" --cookie cookies.txt --header "Content-Type:text/html" https://example.com/path > result.html
Returns gibberish (some sort of js object maybe?), but I am expecting html. Is there a way to retrieve the data that would be in res using cURL?
Thanks in advance.
Sometimes servers send back compressed content. It looks like random garbage. Use curl --compressed to get the decompressed result.
It seems that you are trying to get a data from a POST request. Server returns you a javascript object. And you are getting it right way, javascript converts returned data to HTML, not cURL. So basically you can't do that.

Understanding POST and JSON.parse in Ruby/Sinatra

I'm trying to understand the chain of events of how to POST a JSON object to a Sinatra API.
There will be a JSON object that will need to be passed through a POST request using Sinatra and here's my code that doesn't want to work:
namespace '/api/v1/registrations' do
post '/' do
my_hash = JSON.parse(request.body.read)
puts my_hash
end
end
Here is some test data I'm trying to post:
curl -H "Content-Type: application/json" -X POST http://localhost:4567/api/v1/registrations/ -d '{"i": "am json"}'
I get this error on the console:
JSON::ParserError - 757: unexpected token at '{i: am':
It seems that I would be able to POST a JSON object to /api/v1/registrations/ and I would see it parsed on the console so I can see it actually did something.
What is request.body.readreally doing? I've Googled my fingers off and I just need a laymans answer on how POSTing JSON works.

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.

How can I specify content-type accepted when requesting a HTTP resource with Ruby?

I have always used open-uri, and open("").read to get content through http. I am using this to access an API, and now I need to specify that what content type is accepted. They provide this example from curl
curl -LH "Accept: text/bibliography; style=bibtex" http://dx.doi.org/10.1038/nrd842
How do I do this with open-uri or another Ruby function?
I'd suggest using the optional options hash of open, e.g.
open("http://dx.doi.org/10.1038/nrd842","Accept" => "text/bibliography; style=bibtex"){|f| f.each {|line| print line}}
yields a result.
See also http://www.ruby-doc.org/stdlib-1.9.3/libdoc/open-uri/rdoc/OpenURI.html

Resources