RESTClient not returning the Server Response Message - ruby-on-rails

I am working on a ruby project which involve using RESTClient to reach out to an API. The API returns a 400 HTTP Status Code for a particular result with an accompanying response message (A JSON Response).
But when I check the response of my call:
response = RESTClient.post(...) {
logger.info response.to_s
}
I am getting a Proxy Server 400 page html:
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
</p>
</body></html>
which is not what I'm expecting.
Please what could be wrong?
Also, the behaviour is different with DEV and TEST Environment. On DEV Environment, it's giving the JSON while on TEST, I'm getting this issue.
Thanks.

If this is your API you can enable response in JSON format to any request. Just add this to your base API controller:
before_filter :default_request_format
private
def default_request_format
request.format = :json
end
If this is not your API you should specify Accept header with JSON content type.

Related

BigCommerce oAuth auth token request always returning 401

I can not figure out what I'm doing wrong. I'm developing an App for BigCommerce and can not get the simple oAuth exchange to work correctly.
The initial get request is being made to https://www.my-app.com/oauth/bigcommerce/auth. This is the code in the controller for that request. It's a Laravel 5.6 app:
use Illuminate\Http\Request;
use Bigcommerce\Api\Client as Bigcommerce;
class BigcommerceOAuthController extends Controller
{
public function auth(Request $request)
{
$object = new \stdClass();
$object->client_id = 'my-client-id';
$object->client_secret = 'my-client-secret';
$object->redirect_uri = 'https://my-app.com/oauth/bigcommerce/auth';
$object->code = $request->get('code');
$object->context = $request->get('context');
$object->scope = $request->get('scope');
$authTokenResponse = Bigcommerce::getAuthToken($object);
$storeHash = str_replace('stores/', '', $request->get('context'));
Bigcommerce::configure(array(
'client_id' => 'my-client-id',
'auth_token' => $authTokenResponse->access_token,
'store_hash' => $storeHash
));
echo "<pre>";
print_r($authTokenResponse);
print_r(Bigcommerce::getTime());
echo "</pre>";
}
}
Every time I try to install my draft app from the BigCommerce control panel, I get an error because $authTokenResponse is not an object. When I debug further into the Bigcommerce\Api\Connection class, I can see that the response from the server is empty, and the status is a 401, which means "Unauthorized".
I can't figure out why I am getting this error. As far as I can see, I'm doing everything right. I've tried urlencoding the string retrieved from $request->get('scope'), since that string becomes unencoded by Laravel, but that didn't seem to help.
I am also confused how this is even supposed to work at all. In the BigCommerce docs, they show this example POST request, which uses application/x-www-form-urlencoded Content-Type and passes the request body as a url encoded string:
POST /oauth2/token HTTP/1.1 Host: login.bigcommerce.com Content-Type:
application/x-www-form-urlencoded Content-Length: 186
client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&code=qr6h3thvbvag2ffq&scope=store_v2_orders&grant_type=authorization_code&redirect_uri=https://app.example.com/oauth&context=stores/{STORE_HASH}
However, if you inspect what's going on in the Connection class, you can see that the Content-Type is being set to application/x-www-form-urlencoded as the docs say, but the request body is being passed in as a json string, not a url string. Shouldn't the request be a url encoded string as the docs suggest?
A couple of things here to check:
Do you have a public URL where you can receive the Auth Callback?
If so, did the store owner registered the app successfully? https://developer.bigcommerce.com/api/registration
When you have the client_id and secret_id. You should have all of the details needed to send a POST request to the BC Auth Token Service at https://login.bigcommerce.com/oauth2/token
The content uses URL encode Make sure to URL encode your content. Be careful of of the encoding of & and = signs when those are actually being used as separators.
More details can be found in this post:
Can BigCommerce Private Apps use OAuth

Error when POST ing through Ruby. Postman works fine

I have a strange issue when trying to POST to a third party website.
When testing using Postman, I get a correct response. However, when trying the same POST via Ruby code, I get a cryptic HTML response page from the website. HTTP Response code is 200. It's just that the website's internal logic throws an error, which should'nt happen if I'm sending the exact same request via code than the request I'm sending via Postman.
Url is: http://www.sunat.gob.pe/cl-at-ittipcam/tcS01Alias
The POST can be generated in the browser when choosing month ("mes") and day ("dia") in the dropboxes shown in that webpage. I have also inspected the network call in this case in the browser console and can find nothing funny.
My code comes straight from the one generated by Postman. I have also tried HTTParty gem with the same error response
require 'uri'
require 'net/http'
url = URI("http://www.sunat.gob.pe/cl-at-ittipcam/tcS01Alias")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["cache-control"] = 'no-cache'
request["content-type"] = 'application/x-www-form-urlencoded'
request["postman-token"] = '3ba1963c-2874-89c2-5e4d-e5be2c13a560'
request.body = "mes=05&anho=2016"
response = http.request(request)
puts response.read_body
A correct response should show an HTML table filled with values. Instead I'm getting an HTML error page.
Any help figuring out the issue would be appreciated.
Edit: the HTML response is not really relevant, since it is a business logic error, not an HTTP error, but here it is:
The thing is: this internal logic error is being triggered because something is different when sending the POST request via code than when sending it via Postman, and I can't figure out what.
"\r\n\r\n.:: Pagina de Errores
::.\r\n\r\n\r\n\r\nBODY
{font-style:normal;font-size:10pt;font-family:Verdana,Arial,Helvetica,sans-serif;}\r\nH1
{font-size:16pt;color:Navy;}\r\nA {color:Navy;}\r\n.msg
{font-style:bold;font-size:14pt;}\r\n.error
{font-style:bold;font-size:14pt;color:Red;}\r\n.datos
{font-size:12pt;}\r\n.soluc {font-size:12pt;}\r\n\r\n\r\nLa aplicación
ha retornado el siguiente problema :\r\n\r\n\r\n\r\n\r\n\r\nAcción a realizar :\r\n\r\n\r\nPor favor intentente nuevamente
realizar la operación, si el problema persiste, avisar a
nuestro webmaster
o\r\ncomunicarse con Atenci\xF3n a Usuarios.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n(function(){var
f5_cspm={f5_p:'NEHEKPGFEEIGMFMPAJJJKDPGKDEIIJJIDBONLBJECPDLCCOBKCPONGDHNEIJOKPPCGMBMAGEAADECGEHHJAAAPLKAANKMODHPLFBCJKHMMCPOAKONNKGFELHONBMHBIO',setCharAt:function(str,index,chr){if(index>str.length-1)return
str;return
str.substr(0,index)+chr+str.substr(index+1);},get_byte:function(str,i){var
s=(i/16)|0;i=(i&15);s=s*32;return((str.charCodeAt(i+16+s)-65)<<4)|(str.charCodeAt(i+s)-65);},set_byte:function(str,i,b){var
s=(i/16)|0;i=(i&15);s=s*32;str=f5_cspm.setCharAt(str,(i+16+s),String.fromCharCode((b>>4)+65));str=f5_cspm.setCharAt(str,(i+s),String.fromCharCode((b&15)+65));return
str;},set_latency:function(str,latency){latency=latency&0xffff;str=f5_cspm.set_byte(str,40,(latency>>8));str=f5_cspm.set_byte(str,41,(latency&0xff));str=f5_cspm.set_byte(str,35,2);return
str;},wait_perf_data:function(){try{var
wp=window.performance.timing;if(wp.loadEventEnd>0){var
res=wp.loadEventEnd-wp.navigationStart;if(res<60001){var
cookie_val=f5_cspm.set_latency(f5_cspm.f5_p,res);window.document.cookie='f5avr1032272937aaaaaaaaaaaaaaaa='+encodeURIComponent(cookie_val)+';path=/';}\nreturn;}}\ncatch(err){return;}\nsetTimeout(f5_cspm.wait_perf_data,100);return;},go:function(){var
chunk=window.document.cookie.split(/\s*;\s*/);for(var
i=0;i"
You need to probably use a GET request to get the table. The server is not responding on the POST request because it has not been configured to respond to it.
The solution is to use:
uri = URI('http://www.sunat.gob.pe/cl-at-ittipcam/tcS01Alias')
request = Net::HTTP::Get.new(uri)
instead of the code with Post.new

How to do Google API batch request using python httplib or urllib2?

After the user authorizes the 'read' permission, I need to fetch all the emails of the user. I have access_token/refresh_token which help me to make individual calls for each email. I want to do batch request for all message_ids to reduce the time involved. Here goes my code for batch request which fails.
import httplib,urllib
def fetch_batch():
headers = {'Authorization' : 'Bearer ya29.swCasdjkfgsdalkfgsadfgasdjhgasdkjfasgdfaksdf', 'Host' : 'www.googleapis.com', 'Content-Type' : 'multipart/mixed; boundary=demoabc_wp'}
body="""demoabc_wp
Content-Type: application/http
GET /gmail/v1/users/uabc.kp1#gmail.com/messages/1497474ajsd
demoabc_wp
Content-Type: application/http
GET /gmail/v1/users/uabc.kp1#gmail.com/messages/149744safdg
demoabc_wp
"""
h = httplib.HTTPConnection('www.googleapis.com')
h.request('POST', '/batch', body, headers)
print h.getresponse().read()
This gives this as response:
<HTML>
<HEAD>
<TITLE>Bad Request</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Bad Request</H1>
<H2>Error 400</H2>
</BODY>
</HTML>
Thanks in advance.
Refer from : https://developers.google.com/gmail/api/guides/batch and Batch fetching messages performance
You messed up the multipart encoding. Try
import httplib,urllib
def fetch_batch():
headers = {'Authorization' : 'Bearer ya29.swCasdjkfgsdalkfgsadfgasdjhgasdkjfasgdfaksdf', 'Host' : 'www.googleapis.com', 'Content-Type' : 'multipart/mixed; boundary=demoabc_wp'}
body="""--demoabc_wp
Content-Type: application/http
GET /gmail/v1/users/uabc.kp1#gmail.com/messages/1497474ajsd
--demoabc_wp
Content-Type: application/http
GET /gmail/v1/users/uabc.kp1#gmail.com/messages/149744safdg
--demoabc_wp--
"""
h = httplib.HTTPSConnection('www.googleapis.com')
h.request('POST', '/batch', body, headers)
print h.getresponse().read()
Note, it is 2 hyphens at the start of any boundary, and 2 additional hyphens at the end if it is the last boundary
The Google APIs Python Client Library provides built-in support for batch requests, and should be an easier solution to maintain in the long run.

Getting Google Contacts in Rails 3 app after successful oauth2 authentication with devise

I've searched around a lot and seen various answers. Some seem like they may be outdated, and others use gems (omnicontacts) that I can't seem to get working with devise.
In my situation, I already get an oauth token from Google successfully. Now I'm trying to send a get request to the url given by Google to get all my contacts. I'm able to do this in Google's oauth2 playground, but not from my rails app.
Here is the relevant code:
require 'net/http'
require 'json'
class User < ActiveRecord::Base
def get_google_contacts(auth_token)
uri = URI.parse("https://www.google.com/m8/feeds/contacts/default/full?oauth_token=#{auth_token}&max-results=50000&alt=json")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # You should use VERIFY_PEER in production
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
contacts = JSON.parse(response.body)
puts contacts
end
end
Notebooks Controller: this is where I want a user to be able to access their contacts from Google.
def show
#contacts = current_user.get_google_contacts(current_user.oauth_token)
end
Here is the error log I get in my local:
JSON::ParserError in NotebooksController#show
746: unexpected token at '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Error
401
(Client Error)!!1</title>
<p><b>401.</b>
<ins>That's an error.</ins></p>
<p>There was an error in your request.
<ins>That's all we know.</ins></p></body></html>'
I think I may be using incompatible techniques to parse the xml I get from Google into json, but that is basically what I want to do. The only Rails related documentation I found in Google API documentation was dated 2009, but it mentioned the gdata gem. Should I be using that?
Thank you so much for any help on this.
EDIT
This is the response I get from Google Oauth2 Playground on a 200 ok (https://developers.google.com/oauthplayground/):
Content-type: application/atom+xml; charset=UTF-8
-content-encoding: gzip
<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom'
xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'
xmlns:gContact='http://schemas.google.com/contact/2008'
xmlns:batch='http://schemas.google.com/gdata/batch' xmlns:gd='http://schemas.google.com/g/2005'>
<id>kaustubh.bhardwaj86#gmail.com</id><updated>2014-01-13T18:34:22.842Z</updated><category
scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/contact/2008#contact'/>
<title type='text'>Kaustubh Bhardwaj's Contacts</title>
EDIT #2
Ok, I've isolated my problem. I'm getting Net::HTTPUnauthorized on my get request. Here is the updated code for the get request I'm making to Google Contacts API:
uri = URI.parse("https://www.google.com/m8/feeds/contacts/default/full?max-results=50000")
# headers = { "access_token" => "#{auth_token}" }
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Get.new(uri.request_uri)
request.initialize_http_header({ "access_token" => "#{auth_token}" })
response = http.request(request)
puts response.code
puts response
That is the same url I am using in Google Oauth2 playground.
I suspect you're setting the token incorrectly. It is more normal to set it in an http header
Authorization: Bearer 0b79bab50daca910b000d4f1a2b675d604257e42
If you set it in the URL, I believe it's access_token=, rather than your oauth_token= but since I never use it this way, I might be wrong.

Retrieving XRDS document in OpenID using Ruby

I am just playing around with the OpenID protocol. I am trying to send Discovery request and retrieve the XRDS document from google . When I try to do it from the terminal using the curl, I am getting the following output
curl --url "https://www.google.com/accounts/o8/id"
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds" xmlns="xri://$xrd*($v*2.0)">
<XRD>
<Service priority="0">
<Type>http://specs.openid.net/auth/2.0/server</Type>
<Type>http://openid.net/srv/ax/1.0</Type>
<Type>http://specs.openid.net/extensions/ui/1.0/mode/popup</Type>
<Type>http://specs.openid.net/extensions/ui/1.0/icon</Type>
<Type>http://specs.openid.net/extensions/pape/1.0</Type>
<URI>https://www.google.com/accounts/o8/ud</URI>
</Service>
</XRD>
</xrds:XRDS>
When I try to do the same from the ruby code, It gives me a 302 error and the url to which it has moved points to the same request url.
<HTML>
<HEAD>
<TITLE>Moved Temporarily</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Moved Temporarily</H1>
The document has moved here.
</BODY>
</HTML>
Code
require 'net/http'
require 'net/https'
require 'uri'
http = Net::HTTP.new(uri.host, uri.port)
response = Net::HTTP.get_response(URI.parse("http://www.google.com/accounts/o8/id"))
puts "#{response.read_body}"
How to get the XRDS through the code and why is it showing different outputs. Can someone explain it?Thanks
Google expects the https protocol, though in your ruby example you use http, hence the 302 error. The following snippet should get you the xrds document:
require 'net/http'
require 'net/https'
require 'uri'
uri = URI.parse('https://www.google.com/accounts/o8/id')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
puts "#{response.read_body}"
As you can see, when you fetch the document from ruby, it returns 302 status code, which means that you should look for location header and follow it, like curl does.
Another answer suggested just hardcoding the valid url, but that isn't a correct solution, since Google could make it return 302 as well and move the document somewhere else.
Not to mention that you should perform full Yadis discovery instead of hoping that you'll get an XRDS document from the url (because, for example, Google might decide that it's a good location for explanation of OpenID, and move the XRDS somewhere else using X-XRDS-Location header).

Resources