Reading the body of a 400 response? - ruby

I am trying to read the body of a 400 response with the rest-client gem. The problem is that rest-client responds to 400 by throwing it as an error, so I can't figure out any way to get the body text.
Here's the motivating example. Consider this call to the facebook graph API:
JSON.parse(RestClient.get("https://graph.facebook.com/me?fields=id,email,first_name,last_name&access_token=#{access_token}"))
If the access_token is expired or invalid, facebook does two things:
Returns a 400 Bad Request HTTP response
Returns JSON in the response body with more info, like this:
{
"error": {
"message": "The access token could not be decrypted",
"type": "OAuthException",
"code": 190
}
}
Because 400 response raises an Error, I can't figure out how to get the body of the response. That is, eg, if I run the GET request above in curl or in my browser, I can see the body, but I can't figure out how to access it in restclient. Here's an example:
begin
fb_response = JSON.parse(RestClient.get("https://graph.facebook.com/me?fields=id,email,first_name,last_name&access_token=#{access_token}"))
rescue => e
# 400 response puts me here
# How can I get the body of the above response now, so I can get details on the error?
# eg, was it an expired token? A malformed token? Something else?
end

From rest-client documentation:
Exceptions
for other cases, a RestClient::Exception holding the Response will be raised; a specific exception class will be thrown for known error codes
begin
RestClient.get 'http://example.com/resource'
rescue => e
e.response
end
You can rewrite your code like:
body = begin
RestClient.get("https://graph.facebook.com/me?fields=id,email,first_name,last_name&access_token=#{access_token}")
rescue => e
e.response.body
end
fb_response = JSON.parse(body)
Or just use RestClient::Exception#http_body to get the response body from the exception. (It's just a shortcut).

Related

Is their a way to create Dummy Response with 500 code in HTTParty

Here my HTTParty code
response = HTTParty.post(api_url,body: form_data,timeout: 5)
rescue Timeout::Error
## create dummy response with 500 error code
response = HTTParty::Response.new()
ensure
response
all I'm trying to do is ensure If the HTTParty is unable to connect the given website create a dummy response body objec
But when I try to create a dummy Response object like this
## response = HTTParty::Response.new(Rack::Request.new(api_url),Rack::Response.new('TimeOut Error',500),'TimeOutError')
but this does not work because my response object does not respond_to to_hash
Can anyone suggest a better way to accomplish the same
In case anybody comes looking after 4 years, one could try the following:
httparty_req = HTTParty::Request.new Net::HTTP::Get, '/'
nethttp_resp = Net::HTTPInternalServerError.new('1.1', 500, 'Internal Server Error')
response = HTTParty::Response.new(httparty_req, nethttp_resp, lambda {''}, body: '')

Ruby's Net::HTTP doesn't get the right answer from google OAuth server

I'm writing a small cli tool, that should check my calendar and do some stuff according to my appointments.
I'm struggling a little bit with the OAuth2 authentication. I've checked the scope and the client_id with the curl tool like this:
curl -d "client_id=12345...&scope=scope=https://www.googleapis.com/auth/calendar.readonly" https://accounts.google.com/o/oauth2/device/code
This way, I get the right response.
{
"device_code" : "somestuff",
"user_code" : "otherstuff",
"verification_url" : "http://www.google.com/device",
"expires_in" : 1800,
"interval" : 5
}
But, when I try to use Net::HTTP in Ruby I just get HTTP state 200. I've done it this way:
res = Net::HTTP.post_form(uri, {'client_id' =>'1234....apps.googleusercontent.com', 'scope' => 'https://www.googleapis.com/auth/calendar.readonly' })
If I check the res variable afterwards I get the state 302, but I guess this is correct.
Can someone tell me what I'm, doing wrong so I don't get the JSON response? Should I try something different than Net::HTTP?
res is a variable containing all the response data, not just the text of the response. If you puts res.body after your post_form() call, you should find your JSON (which you can parse with the JSON module).

How do I output error messages with HTTP error codes in Sinatra?

I'm trying to handle errors nicely using Sinatra. For example, say I have a block like this:
get '/auth/' do
...
begin
access_token_obj = OAuth2::AccessToken.new(client, token)
rescue OAuth2::Error => e
return 403, e.description
rescue
return 403, "Something went wrong"
end
...
end
I want to display a nice error page to the user. The Sinatra docs suggest I can do something like:
error 403 do
"Access forbidden"
end
But how do I get the error message ("Something went wrong" or e.description) to display to the user? In my error 403 do block there is no env['sinatra.error'] available. I'm obviously missing something (I'm a bit new to ruby).
Look in the body variable, you'll have the error message in the first index, so in body[0].

How to parse HTTP response using Ruby

I've written a short snippet which sends a GET request, performs auth and checks if there is a 200 OK response (when auth success). Now, one thing I saw with this specific GET request, is that the response is always 200 irrespective of whether auth success or not.
The diff is in the HTTP response. That is when auth fails, the first response is 200 OK, just the same as when auth success, and after this then there is a second step. The page gets redirected again to the login page.
I am just trying to make a quick script which can check my login user and pass on my web application and tell me which auth passed and which didn't.
How should I check this? The sample code is like this:
def funcA(u, p)
print_A("#{ip} - '#{u}' : '#{p}' - Pass")
end
def try_login(u, p)
path = '/index.php?uuser=#{u}&ppass=#{p}'
r = send_request_raw({
'URI' => 'path',
'method' => 'GET'
})
if (r and r.code.to_i == 200)
check = true
end
if check == true
funcA(u, p)
else
out = "#{ip} - '#{u} - Fail"
print_B(out)
end
return check, r
end
end
Update:
I also tried adding a new check for matching a 'Success/Fail' keyword coming in HTTP response. It didn't work either. But I now noticed that the response coming back seems to be in a different form. The Content-Type in response is text/html;charset=utf-8 though. And I am not doing any parsing so it is failing.
Success Response is in form of:
{"param1":1,"param2"="Auth Success","menu":0,"userdesc":"My User","user":"uuser","pass":"ppass","check":"success"}
Fail response is in form of:
{"param1":-1,"param2"="Auth Fail","check":"fail"}
So now I need some pointers on how to parse this response.
Many Thanks.
I do this with with "net/http"
require 'net/http'
uri = URI(url)
connection = Net::HTTP.start(uri.host, uri.port)
#response = Net::HTTP.get_response(URI(url))
#httpStatusCode = #response.code
connection.finish
If there's a redirect from a 200 then it must be a javascript or meta redirect. So just look for that in the response body.

how can I handle "error" in communication to twitter.com? (ruby + twitter gem)

I have nice piece of code that works. I tried to tweet the same text and I my script ended because /lib/ruby/gems/1.8/gems/twitter-0.9.4/lib/twitter.rb:87:in 'raise_errors': (403): Forbidden - Status is a duplicate. (Twitter::General)
I know I cannot tweet the same text twice but I thought I will get the error inside the response variable.
How can I deal with the error? So my script will finish nicely not because of an error?
oauth = Twitter::OAuth.new('consumer token', 'consumer secret')
oauth.authorize_from_access('access token', 'access secret')
client = Twitter::Base.new(oauth)
response = client.update('Heeeyyyyoooo from Twitter Gem!')
You can wrap any ruby statement or block of statements in begin..rescue..end to catch errors - you might want to try this:
begin
oauth = Twitter::OAuth.new('consumer token', 'consumer secret')
oauth.authorize_from_access('access token', 'access secret')
client = Twitter::Base.new(oauth)
response = client.update('Heeeyyyyoooo from Twitter Gem!')
rescue Twitter::General
# Catch the error and do nothing
end
If you wanted to catch any error you can change the rescue line to just say rescue. You can read more about them on the ruby-doc website.

Resources