Simplest way to do a XMLHttpRequest in Ruby? - ruby

I want to do a XMLHttpRequest POST in Ruby. I don't want to use a framework like Watir. Something like Mechanize or Scrubyt would be fine. How can I do this?

Mechanize:
require 'mechanize'
agent = Mechanize.new
agent.post 'http://www.example.com/', :foo => 'bar'

Example with 'net/http', (ruby 1.9.3):
You only have to put an additional header for the XMLHttpRequest to your POST-request (see below).
require 'net/http'
require 'uri' # convenient for using parts of an URI
uri = URI.parse('http://server.com/path/to/resource')
# create a Net::HTTP object (the client with details of the server):
http_client = Net::HTTP.new(uri.host, uri.port)
# create a POST-object for the request:
your_post = Net::HTTP::Post.new(uri.path)
# the content (body) of your post-request:
your_post.body = 'your content'
# the headers for your post-request (you have to analyze before,
# which headers are mandatory for your request); for example:
your_post['Content-Type'] = 'put here the content-type'
your_post['Content-Length'] = your_post.body.size.to_s
# ...
# for an XMLHttpRequest you need (for example?) such header:
your_post['X-Requested-With'] = 'XMLHttpRequest'
# send the request to the server:
response = http_client.request(your_post)
# the body of the response:
puts response.body

XMLHTTPRequest is a browser concept, but since you're asking about Ruby, I assume all you want to do is simulate such a request from a ruby script? To that end, there's a gem called HTTParty which is very easy to use.
Here's a simple example (assuming you have the gem - install it with gem install httparty):
require 'httparty'
response = HTTParty.get('http://twitter.com/statuses/public_timeline.json')
puts response.body, response.code, response.message, response.headers.inspect

Related

TypeError problem: no implicit conversion in Sinatra + JSON.parse

I'm trying to set up a web hook, following this GitHub tutorial
require 'sinatra'
require 'json'
require 'net/http'
require 'pp'
set :port, 31415
# Descarga las diferencias hechas para un push
post '/' do
push = JSON.parse(request.body.read)
piezas = push["compare"].split("/")
api_url = "/repos/#{piezas[3]}/#{piezas[4]}/compare/#{piezas[6]}"
diff = Net::HTTP.get(URI("https://api.github.com#{api_url}"))
puts diff.class
pp(JSON.parse(diff))
end
diff.class prints:
String
And, as a matter of fact, the last sentence works correctly, printing via pp the structure. However, after printing, it yields the error
[2018-10-25 20:00:23] ERROR TypeError: no implicit conversion of Array into String
It's not referencing any line in the script, but would it be possible that the error would be in the first JSON.parse? Could it be that request.body.read would be an array?
Update I couldn't golf it down to any of the JSON.parse separately. Downloading the hook payload works OK, downloading the JSON from the GitHub API works without a glithc. Somehow it's using them together what does not work.
It's possible the library is treating the response like text. Try adding an Accept header. This worked for me:
request["Accept"] = "application/json"
example:
uri = URI.parse("https://api.github.com")
req = Net::HTTP::Get.new(URI("https://api.github.com/repos/JJ/microservices-broker/compare/d5d39c5db99d...bbbf695d1bf2"))
req["Accept"] = 'application/json'
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
response = http.request(req)
json = JSON.parse(response.body)
json['url']
# or
json = JSON.parse(response.body, symbolize_names: true)
json[:url]
(EDIT:) Also, Using Net::HTTP is really painful. Please checkout these libraries:
https://github.com/lostisland/faraday
https://github.com/octokit/octokit.rb

Using Ruby's Net/HTTP module, can I ever send raw JSON data?

I've been doing a lot of research on the topic of sending JSON data through Ruby HTTP requests, compared to sending data and requests through Fiddler. My primary goal is to find a way to send a nested hash of data in an HTTP request using Ruby.
In Fiddler, you can specify a JSON in the request body and add the header "Content-Type: application/json".
In Ruby, using Net/HTTP, I'd like to do the same thing if it's possible. I have a hunch that it isn't possible, because the only way to add JSON data to an http request in Ruby is by using set_form_data, which expects data in a hash. This is fine in most cases, but this function does not properly handle nested hashes (see the comments in this article).
Any suggestions?
Although using something like Faraday is often a lot more pleasant, it's still doable with the Net::HTTP library:
require 'uri'
require 'json'
require 'net/http'
url = URI.parse("http://example.com/endpoint")
http = Net::HTTP.new(url.host, url.port)
content = { test: 'content' }
http.post(
url.path,
JSON.dump(content),
'Content-type' => 'application/json',
'Accept' => 'text/json, application/json'
)
After reading tadman's answer above, I looked more closely at adding data directly to the body of the HTTP request. In the end, I did exactly that:
require 'uri'
require 'json'
require 'net/http'
jsonbody = '{
"id":50071,"name":"qatest123456","pricings":[
{"id":"dsb","name":"DSB","entity_type":"Other","price":6},
{"id":"tokens","name":"Tokens","entity_type":"All","price":500}
]
}'
# Prepare request
url = server + "/v1/entities"
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.set_debug_output( $stdout )
request = Net::HTTP::Put.new(uri )
request.body = jsonbody
request.set_content_type("application/json")
# Send request
response = http.request(request)
If you ever want to debug the HTTP request being sent out, use this code, verbatim: http.set_debug_output( $stdout ). This is probably the easiest way to debug HTTP requests being sent through Ruby and it's very clear what is going on :)

Sending file with POST to server in pure ruby (or library that doesn't need build tools)

Writing extensions for Sketchup I need to get around their usage of their own ruby (2.0.0) interpreter. Most importantly, I can't install gems that require build tools.
How can I send a file per POST request to my local server which does some calculations and answers with a JSON object?
I'm aware how I can use rest-client to send the file, but due the mentioned restrictions I can't use it (it required build tools). Is there another comparable way or library that can help me?
require 'uri'
url = 'http://foourl.com'
uri = URI.parse(url)
data = File.read('fil_path')
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.body = data
request.content_type = 'audio/amr'
response = http.request(request)
(Taken from here)
Don't forget to configure your content type
You can use Ruby's native Net::HTTP library.
Examples:
require 'net/http'
require 'uri'
uri = URI('http://www.example.com/search.cgi')
res = Net::HTTP.post_form(uri, 'q' => 'ruby', 'max' => '50')
puts res.body
or
response = http.post('/cgi-bin/search.rb', 'query=foo')

Imdb api with Ruby

I am trying to use the imdb API. I tried to search for Fargo, but when I run it, all I get is a black screen:
require 'net/http'
uri = URI.parse("http://imdbapi.org/")
response = Net::HTTP.post_form(uri, {"q" => "Fargo"})
Can anyone tell me what is wrong or provide an example on how to retrieve the data from Fargo with a json in ruby from that api?
Simple way:
require 'json'
require 'open-uri'
json = JSON.parse(open("http://imdbapi.org?q=Fargo") { |x| x.read }).first
To get individual element:
json['title']
#=> Fargo
This simple code below show us how to get a basic json data from imdb api:
require "net/http"
require "uri"
uri = URI.parse("http://imdbapi.org/?title=Fargo&type=json")
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
response = http.request(request)
puts response.body
I use a verb GET in the REST way.

How do I use ruby get JSON back from Instagram API

I am doing my best to get JSON back from the instagram API. Here is the code I am trying in my rake task within rails.
require 'net/http'
url = "https://api.instagram.com/v1/tags/snow/media/recent?access_token=522219.f59def8.95be7b2656ec42c08bff8a159a43d06f"
resp = Net::HTTP.get_response(URI.parse(url))
puts resp.body
All I end up with in the terminal is "rake aborted!
end of file reached"
If you look at the instagram docs http://instagram.com/developer/endpoints/tags/ and you paste the following URL in your browser you will get JSON back so I'm sure I am doing something wrong.
https://api.instagram.com/v1/tags/snow/media/recent?access_token=522219.f59def8.95be7b2656ec42c08bff8a159a43d06f
It has to do with HTTPS url you need to modify your code to include SSL
require "net/https"
require "uri"
uri = URI.parse("https://api.instagram.com/v1/tags/snow/media/recent?access_token=522219.f59def8.95be7b2656ec42c08bff8a159a43d06f")
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)
response = http.request(request)
puts response.body
alternatively you could use somthing like https://github.com/jnunemaker/httparty to consume 3rd party services
Looks like you'd need to configure net/http to use SSL because you're using https.
Alternative : use this with Rails, it'll parse the json on the fly too :
ActiveSupport::JSON.decode(open(URI.encode(url)))
Returns a hash to play with

Resources