HTTParty parsed_response returns a String instead of Hash - ruby

HTTParty's parsed_response method returns a Hash if you get a response code 200 but otherwise it will return a String regardless if the webserver returns a XML response.
HTTParty.get(post_url).parsed_response.class # Depends on response code
Amazon will provide XML (explaining what went wrong) even on a 403.
Am I missing something?

HTTParty parses its #parsed_response based on what the HTTP response's Content-Type header is. Verify what the value is for that HTTP header. In your case, you'd want it to be application/xml.

In case anyone is still encountering this issue today, get can take a format parameter, which can help you ensure your HTTParty::Response object is a Hash:
url = HTTParty.get('http://domain.com', format: :json) # class is a Hash

Related

http.post request not receiving any data

I have a program that sends an HTTP request and receive the answer.
http = Net::HTTP.new(server, port)
resp, data = http.post(path, url, headers)
After this I see resp with a value of #<Net::HTTPOK:0x00005643dd572980> and data empty, so I receive a
no implicit conversion of nil into String error afterwards when I use it.
I have never used Ruby so I'm a bit confused about what can be failing or how I can debug this. I capture network traffic and both the request and response are sent correctly, and the response contains the expected data.
Is there anything that can make data be empty? How can I debug this?
Per the documentation, the Net::HTTP post method returns an HTTPResponse object. Since there is only one object returned, only resp will be given a value.
You mentioned that "the response contains the expected data." I am wondering if you simply need to employ the body method. Does resp.body give you the data you are looking for?
See https://ruby-doc.org/stdlib-2.7.1/libdoc/net/http/rdoc/Net/HTTP.html#method-i-post

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.

variables post in koa framework

hi where is the data in post call in koa without co-body or bodyparse or why this error
Error: invalid JSON, only supports object and array
at parse (d:\Proyectos\koaJsTest\node_modules\co-body\lib\json.js:56:13)
co-body performs this regex unless the "strict" option is set to false:
/^[\x20\x09\x0a\x0d]*(\[|\{)/
Perhaps your json is making it to co-body as a URL-encoded string?
Its either going to be the format of the JSON that you are uploading if you are setting the Content-Type to application/json.
Otherwise, may be using the wrong Content-Type. For example if you were uploading files where the Content-Type should be multipart/form-data but you accidentally set the Content-Type to application/json when it should you would see this error.
This has tripped me up in the past.

HTTParty returning a string

I am using an API which is returning the wrong mime type, it's coming out as text/html rather than application/json.
Some of the responses are application/json so I know that the problem is due to mime type.
But for the text/html (which returns valid json with the wrong mime type) httparty will only parse this into a string rather than a hash.
Is there a way to parse this string into a hash?
I've tried using require 'json' but using JSON.parse comes up with an unexpected key error.
If you're extending a class with HTTParty try adding
format :json
to the class
also make sure you're parsing the body of the response and not the response object.
JSON.parse(get(self.class.get("some_url","some_params").body)
Without code or API URL I can only guess. Perhaps the API can respond in multiple ways and you need the appropriate Accept header.
class Foo
include HTTParty
headers 'Accept' => 'application/json'
end

Post request with body_stream and parameters

I'm building some kind of proxy.
When I call some url in a rack application, I forward that request to an other url.
The request I forward is a POST with a file and some parameters.
I want to add more parameters.
But the file can be quite big. So I send it with Net::HTTP#body_stream instead of Net::HTTP#body.
I get my request as a Rack::Request object and I create my Net::HTTP object with that.
req = Net::HTTP::Post.new(request.path_info)
req.body_stream = request.body
req.content_type = request.content_type
req.content_length = request.content_length
http = Net::HTTP.new(#host, #port)
res = http.request(req)
I've tried several ways to add the proxy's parameters. But it seems nothing in Net::HTTP allows to add parameters to a body_stream request, only to a body one.
Is there a simpler way to proxy a rack request like that ? Or a clean way to add my parameters to my request ?
Well.. as i see it, this is a normal behaviour. I'll explain why. If you only have access to a Rack::Request,(i guess that) your middleware does not parse the response (you do not include something like ActionController::ParamsParser), so you don't have access to a hash of parameters, but to a StringIo. This StringIO corresponds to a stream like:
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="param1"
value1
--AaB03x
Content-Disposition: form-data; name="files"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
What you are trying to do with the Net::HTTP class is to: (1). parse the request into a hash of parameters; (2). merge the parameters hash with your own parameters; (3). recreate the request. The problem is that Net::HTTP library can't do (1), since it is a client library, not a server one.
Therefore, you can not escape parsing some how your request before adding the new parameters.
Possible solutions:
Insert ActionController::ParamsParser before your middleware. After that, you may use the excellent rest-client lib to do something like:
RestClient.post ('http://your_server' + request.path_info), :params => params.merge(your_params)
You can attempt to make a wrapper on the StringIO object, and add, at the end of stream,your own parameters. However, this is not trivial nor advisable.
Might be one year too late, but I had the same issue verifying Paypal IPNs. I wanted to forward back the IPN request to Paypal for verification but needed to add :cmd => '_notify-validate'.
Instead of modifying the body stream, or body, I appended it as part of the URL path, like so:
reply_request = Net::HTTP::Post.new(url.path + '?cmd=_notify-validate')
It seems a bit of a hack, but I think it's worth it if you aren't going to use it for anything else.

Resources