Error when POST ing through Ruby. Postman works fine - ruby-on-rails

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

Related

Postman post request works ok but exported Ruby Don

Post request work in Postman but the same code exported in Ruby doesn't work. It is a request
Content-Type= application/x-www-form-urlencoded with body
content-type = 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW'
I need to send a confirmation to payU for IDN. The request works ok if it is send from Postman but not working ok when I ran the same code from ruby. (their server's answer is "Invalid account code" which is equivalent with no parameters received by payU.)
Request makes a post requests to
https://sandbox.payu.ro/order/idn.php
with header:
Content-Type:application/x-www-form-urlencoded
with
body: multipart/form-date and the parameters:
MERCHANT=GOISTEST
ORDER_REF=304911
ORDER_AMOUNT=35.70
ORDER_CURRENCY=RON
IDN_DATE=2019-05-26 07:50:39
ORDER_HASH=b27e42645e9c52b81fab955eb7309f70
The Postman request result is
<EPAYMENT>304911|7|Order already confirmed|2019-05-26 08:57:52|5c25acc698cb607a2af3676fdbaabf7b</EPAYMENT>
If you export in Ruby and run it you get an error for Error EOF
but if you add:
http.use_ssl = true
then the request is done and response is:
"Invalid account code"
I would need the request to work in ruby!
This is the code exported by postman to Ruby:
The Postman request result is
<EPAYMENT>304911|7|Order already confirmed|2019-05-26 08:57:52|5c25acc698cb607a2af3676fdbaabf7b</EPAYMENT>
If you export in Ruby and run it you get an error for Error EOF
but if you add:
http.use_ssl = true
then the request is done and response is:
"Invalid account code"
This is the server's answer when you do not send the parameters at all!
"What more can I do? "
In the end I found out from that
http://ruby-doc.org/stdlib-2.0.0/libdoc/net/http/rdoc/Net/HTTP.html#label-Setting+Headers
that
request["content-type"] = 'multipart/form-data; boundary=----NEW_BOUNDARY'
is not working but
request.content_type = 'multipart/form-data; boundary=----NEW_BOUNDARY'
works.
I could make finnaly the post after many hours of debugging.

How to get the status after sending data to external server rails

In my rails (3.2.13) app I send data to an external server using a form, then the external server process the data I sent and shows that the result is ok or not, I need to save that result or status to my rails app database, but I'm not sure about how to redirect to another page when the process in the external server is done.
I have a function to ask the server if the process of that data went ok using the reference or id that I sent in the first place using the form but as I said I don't know how to redirect after the process is finish...
please help me
You can use some core Ruby libraries to make a subsequent request on the same endpoint to determine the status code of your request. Try the following, cited in whole from Ruby Inside:
# Basic REST.
# Most REST APIs will set semantic values in response.body and response.code.
require "net/http"
http = Net::HTTP.new("api.restsite.com")
request = Net::HTTP::Post.new("/users")
request.set_form_data({"users[login]" => "quentin"})
response = http.request(request)
# Use nokogiri, hpricot, etc to parse response.body.
request = Net::HTTP::Get.new("/users/1")
response = http.request(request)
# As with POST, the data is in response.body.
request = Net::HTTP::Put.new("/users/1")
request.set_form_data({"users[login]" => "changed"})
response = http.request(request)
request = Net::HTTP::Delete.new("/users/1")
response = http.request(request)
Once you've instantiated a response object, you can operate on it in the following manner:
response.code #=> returns HTTP response code

YouTube API: Delete video HTTP request from Ruby not working

I am trying to delete a video on YouTube from a Ruby on Rails application. I am following these instructions, from the YouTube API docs:
DELETE /feeds/api/users/default/uploads/VIDEO_ID HTTP/1.1
Host: gdata.youtube.com
Content-Type: application/atom+xml
Authorization: Bearer ACCESS_TOKEN
GData-Version: 2
X-GData-Key: key=DEVELOPER_KEY
I am not very familiar with Ruby's Net::HTTP class, but it seems that no matter what I try I cannot get the request to work properly. I have looked carefully at the many other StackOverflow questions regarding deleting videos from YouTube, but none that I could find address this particular problem. My code is below, where I've replaced the user name, video ID, access token, and developer key.
url = URI.parse("https://gdata.youtube.com/feeds/api/users/[USER_NAME]/uploads/[VIDEO_ID]")
post_args = { 'Host' => 'gdata.youtube.com', 'GData-Version' => '2', 'Content-Type' => 'application/atom+xml', 'Authorization' => "Bearer [ACCESS_TOKEN]", 'X-GData-Key' => 'key=[DEVELOPER_KEY]' }
req = Net::HTTP::Delete.new(url.path)
req.set_form_data(post_args)
httpreq = Net::HTTP.new(url.host, url.port)
httpreq.use_ssl = true
resp = httpreq.start {|http| http.request(req) }
Checking the response, I get an Error 400 (Bad Request) from YouTube. The response simply says "Your client has issued a malformed or illegal request. That's all we know".
Is there something wrong with the request I'm making? I've checked it against the template time and time again and I can't see anything wrong with it. I know that my access token and developer key are working because I can make other requests like video uploads just fine.
I printed the debug output from the HTTP request, and as far as I can tell it looks fine:
<- "DELETE /feeds/api/users/[USER_NAME]/uploads/[VIDEO_ID] HTTP/1.1\r\nAccept: */*\r\nUser-Agent: Ruby\r\nContent-Type: application/x-www-form-urlencoded\r\nHost: gdata.youtube.com\r\nContent-Length: 275\r\n\r\n"
<- "Host=gdata.youtube.com&GData-Version=2&Content-Type=application%2Fatom%2Bxml&Authorization=Bearer+[ACCESS_TOKEN]&X-GData-Key=key%3D[DEVELOPER_KEY]"
The only thing I could see as a possible problem was that in the first line of the request, the "Content-Type" is set to "application/x-www-form-urlencoded". Again, not being an expert on HTTP requests I'm not sure what the difference is between the Content-Type set in the first line and the Content-Type that I explicitly set as "application/atom+xml" which appears on the second line of the request. After some digging, though, I found out that the set_form_data method automatically sets the content type as "application/x-www-form-urlencoded", so I tried adding the following line to my code:
req.content_type = 'application/atom+xml'
right after the line
req.set_form_data(post_args)
When I do this, I do see a corresponding change in the request:
<- "DELETE /feeds/api/users/[USER_ID]/uploads/[VIDEO_ID] HTTP/1.1\r\nAccept: */*\r\nUser-Agent: Ruby\r\nContent-Type: application/atom+xml\r\nHost: gdata.youtube.com\r\nContent-Length: 275\r\n\r\n"
<- "Host=gdata.youtube.com&GData-Version=2&Content-Type=application%2Fatom%2Bxml&Authorization=Bearer+[ACCESS_TOKEN]&X-GData-Key=key%3D[DEVELOPER_KEY]"
However, I still get the exact same response from YouTube. Error 400, bad request. What the heck is going on here??
Of course, 10 minutes after asking my question, I find out the answer. I did not understand the distinction between the HTTP header fields and form arguments, which I don't feel so bad about since it's not explained anywhere either in the Ruby documentation on Net::HTTP or in the YouTube API. The reason I was confused was because for uploading a video, you can provide all the values like Authorization and Content-Type as form data, so the above approach from my question works fine. For deleting a video, you have to provide those values as part of the header, not form data. At least, that is now my understanding.
Anyway, in case anyone ever runs into this problem, this solved it for me:
req = Net::HTTP::Delete.new(url.path)
req['GData-Version'] = '2' # this syntax sets header fields & values
req['Authorization'] = "..."
req['X-GData-Key'] = "..."
req.content_type = 'application/atom+xml'
httpreq = Net::HTTP.new(url.host, url.port)
httpreq.use_ssl = true
resp = httpreq.start {|http| http.request(req) }
Another case where one explanatory sentence from the authors of the documentation would have saved two hours of wasted time. If I had a nickel...

403 Developer Inactive on an HTTP pull

I am trying to query some XML from a hotel database using Ruby, and am getting the results:
403 Developer Inactive
I used the code:
require 'net/http'
url = URI.parse('URL of the HTTP query')
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) {|http|
http.request(req)
}
puts res.body
I would give the actual URL, but it contains the API key/etc...so I really cannot divulge it.
Is there anything wrong with the code or might it be on the company needing to activate the key?
Thanks
403 is the HTTP status code FORBIDDEN, which leads me to believe you have a problem authenticating your API request, maybe because of a wrong key or something.

Google Geocoding API request_denied

I am trying to geocode a batch of around 400 addresses using the Google Geocoding API through my rails app.
In one of my controllers I have these lines
require "net/http"
require "uri"
uri = URI.parse("http://maps.googleapis.com/maps/api/geocode/json?")
response = Net::HTTP.post_form(uri, {"address" => '5032-forbes-ave', 'sensor' => 'false'})
But I always get back ""status": "REQUEST_DENIED" from that.
Does anyone know why I am getting this, or if there is a way I can see exactly the HTTP request that is being sent so I can try to debug it?
Update: This is the request that I am trying to make, if I do this from my browser I get a normal response from the api: http://maps.googleapis.com/maps/api/geocode/json?address=5032-forbes-ave&sensor=false
You are POSTing the request but in your browser you are using GET.
So this work perfectly:
uri = URI.parse("http://maps.googleapis.com/maps/api/geocode/json?address=5032-forbes-ave&sensor=false")
response = Net::HTTP.get(uri)
The response is String itself and it contains some JSON (I'm not Google API's expert)

Resources