Query server with PUT method - ruby-on-rails

I will replace my command line
`curl -XPUT 'host:port/url' -d '{"val": "some_json"}'̀
by a Rails command, and get the result...
Somewhere like this :
response = call('put', 'host:port/url', '{"val" : "some_json"}')
Is there any predefined method to do this in Rails, or some gem ?
I know the command get of HTTP, but I will do a 'PUT' method.
Net::HTTP.get(URI.parse('host:port/url'))
Thanks for your replies

You can use Net::HTTP to send any standard http requests.
Here is a way, you can connect to any url ( http / https ), with any valid http methods with or without parameters.
def universal_connector(api_url, api_parameters={}, method="Get")
# Do raise Error, if url is invalid and Method is invalid
uri = URI(api_url)
req = eval("Net::HTTP::#{method.capitalize}.new('#{uri}')")
req.set_form_data(api_parameters)
Net::HTTP.start(uri.host, uri.port,:use_ssl => uri.scheme == 'https') do |http|
response = http.request(req)
return response.body
end
end
There are many alternatives available as well. Specifically, Faraday. Also, read this before making a choice.

#get is just a simple shortcut for the whole code (Net::HTTP Ruby library tends to be very verbose). However, Net::HTTP perfectly supports PUT requests.
Another alternative is to use an HTTP client as a wrapper. The most common alternatives are HTTParty and Faraday.
HTTParty.put('host:port/url', { body: {"val" : "some_json"} })
As a side note, please keep in mind that Rails is a framework, not a programming language. Your question is about how to perform an HTTP PUT request in Ruby, not Rails. It's important to understand the difference.

Related

Ruby NET::HTTP Read the header BEFORE the body (without HEAD request)?

I'm using Net::HTTP with Ruby to crawl an URL.
I don't want to crawl streaming audio such as: http://listen2.openstream.co/334
in fact i only want to crawl Html content, so no pdfs, video, txt..
Right now, I have both open_timeout and read_timeout set to 10, so even if I do crawl these streaming audio pages they will timeout.
url = 'http://listen2.openstream.co/334'
path = uri.path
req= Net::HTTP::Get.new(path, {'Accept' => '*/*', 'Content-Type' => 'text/plain; charset=utf-8', 'Connection' => 'keep-alive','Accept-Encoding' => 'Identity'})
uri = Addressable::URI.parse(url)
resp = Net::HTTP.start(uri.host, uri.inferred_port) do |httpRequest|
httpRequest.open_timeout = 10
httpRequest.read_timeout = 10
#how can I read the headers here before it's streaming the body and then exit b/c the content type is audio?
httpRequest.request(req)
end
However, is there a way to check the header BEFORE I read the body of a http response to see if it's an audio? I want to do so without sending a separate HEAD request.
net/http supports streaming, you can use this to read the header before the body.
Code example,
url = URI('http://stackoverflow.com/questions/41306082/ruby-nethttp-read-the-header-before-the-body-without-head-request')
Net::HTTP.start(url.host, url.port) do |http|
request = Net::HTTP::Get.new(url)
http.request(request) do |response|
# check headers here, body has not yet been read
# then call read_body or just body to read the body
if true
response.read_body do |chunk|
# process body chunks here
end
end
end
end
I will add a ruby example later tonight. However, for a quick response. There is a simple trick to do this.
You can use HTTP Range header to indicate if which range of bytes you want to receive from the server. Here is an example:
curl -XGET http://www.sample-videos.com/audio/mp3/crowd-cheering.mp3 -v -H "Range: bytes=0-1"
The above example means the server will return data from 0 to 1 byte range.
See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
Since I did not find a way to properly do this in Net::HTTP, and I saw that you're using the addressable gem as an external dependency already, here's a solution using the wonderful http gem:
require 'http'
response = HTTP.get('http://listen2.openstream.co/334')
# Here are the headers
puts response.headers
# Everything ok? Start streaming the response
body = response.body
body.stream!
# now just call `readpartial` on the body until it returns `nil`
# or some other break condition is met
Sorry if you're required to use Net::HTTP, hopefully someone else will find an answer. A separate HEAD request might indeed be the way to go in that case.
You can do a whole host of net related things without using a gem. Just use the net/http module.
require 'net/http'
url = URI 'http://listen2.openstream.co/334'
Net::HTTP.start(url.host, url.port){|conn|
conn.request_get(url){|resp|
resp.each{|k_header, v_header|
# process headers
puts "#{k_header}: #{v_header}"
}
#
# resp.read_body{|body_chunk|
# # process body
# }
}
}
Note: while processing headers, just make sure to check the content-type header. For audio related content it would normally contain audio/mpeg value.
Hope, it helped.

What are some guidelines for creating HTTP requests in a Rails app?

I am relatively new to writing code against REST APIs. It is possible I am analyzing the wrong problem here, so feel free to give big picture advice. The other twist is that the API I want to use is not yet configured, so I can't test.
I need to write some Rails code to create webhooks on the Jive API. Jive's docs show how to register the webservice via a curl request. I want to build the code as an admin function of my app in case we need to recreate the webhook for any reason.
Here are the Jive Docs.
Based on this guide, I'm thinking I need something like (I expect this example to sent a POST request to "sample.jiveon.com/api/core/v3/webhooks"):
#host = "sample.jiveon.com/api/core/v3"
#port = "443"
#post_ws = "/webhooks"
#payload ={
"events" => "document",
"callback" => "my_app/jive_listener",
"object" => "my/jive/space"
}.to_json
def post
req = Net::HTTP::Post.new(#post_ws, initheader = {'Content-Type' =>'application/json'})
req['Authorization'] = "Bearer my_key"
req.body = #payload
response = Net::HTTP.new(#host, #port).start {|http| http.request(req) }
end
end
Thanks.
It would be better to use gem like 'rest-client(https://github.com/rest-client/rest-client)'
Above gem does the many stuff, which you might be doing manually using bare ruby library. It depends on need of yours.

Ruby Proxy Authentication GET/POST with OpenURI or net/http

I'm using ruby 1.9.3 and trying to use open-uri to get a url and try posting using Net:HTTP
Im trying to use proxy authentication for both:
Trying to do a POST request with net/http:
require 'net/http'
require 'open-uri'
http = Net::HTTP.new("google.com", 80)
headers = { 'User-Agent' => 'Ruby 193'}
resp, data = http.post("/", "name1=value1&name2=value2", headers)
puts data
And for open-uri which I can't get to do POST I use:
data = open("http://google.com/","User-Agent"=> "Ruby 193").read
How would I modify these to use a proxy with HTTP Authentication
I've tried (for open-uri)
data = open("http://google.com/","User-Agent"=> "Ruby 193", :proxy_http_basic_authentication => ["http://proxy.com:8000/", "proxy-user", "proxy-password"]).read
However all I will get is a OpenURI::HTTPError: 407 Proxy Authentication Required. I've verified all and it works in the browser with the same authentication and proxy details but I can't get ruby to do it.
How would I modify the code above to add http authentication properly? Has anyone gone through this atrocity?
Try:
require "open-uri"
proxy_uri = URI.parse("http://proxy.com:8000")
data = open("http://www.whatismyipaddress.com/", :proxy_http_basic_authentication => [proxy_uri, "username", "password"]).read
puts data
As for Net::HTTP, I recently implemented support for proxies with http authentication into a Net::HTTP wrapper library called http. If you look at my last pull-request, you'll see the basic implementation.
EDIT: Hopefully this will get you moving in the right direction.
Net::HTTP::Proxy(proxy_uri.host, proxy_uri.port,"username","password").start('whatismyipaddress.com') do |http|
puts http.get('/').body
end
EDIT 11/24/2020: Net::HTTP::Proxy is now considered obsolete. You can now configure proxies when creating a new instance of Net::HTTP. See the documentation for Net::HTTP.new for more details.

Setting outgoing IP address in open-uri with RoR

I'm new to open-uri and trying to set an outgoing IP address using open-uri in ruby on rails. I used this post as a reference to get started. I'm porting an app from PHP where I could use CURLOPT_INTERFACE in curl_setopt. What's the best way to do this using open-uri in rails? (Doing this from the controller - not command line.)
If there's not a way to do this - any suggestions on an alternative to open-uri? My goal is to take in and parse JSON data.
What I understand from your questions is you want to hit another server from a specific IP which suggests you have a server with couple of addresses.
What I can suggest you is try to execute curl directly and do what you want to do or use a wrapper for it.
Doesn't look like open-uri can do this. But with net/https it's fairly easy.
require 'net/https'
require 'json'
uri = URI('https://jsonvat.com/')
http = Net::HTTP.new(uri.host, uri.port)
http.local_host = '1.2.3.4'
http.use_ssl = true
request = Net::HTTP::Get.new('/')
request.content_type = 'application/json'
request.initialize_http_header('Content-Type' => 'application/json')
response = http.request(request)
json = JSON.parse(response.body)
Probably you don't need the "require" lines inside Rails Controllers.
You can specify the outgoing IP address with the http.local_host line.
https://stackoverflow.com/a/24896074/1371731
https://yukimotopress.github.io/http

Using Ruby on Rails to POST JSON/XML data to a web service

I built a web service in using Spring framework in Java and have it run on a tc server on localhost. I tested the web service using curl and it works. In other words, this curl command will post a new transaction to the web service.
curl -X POST -H 'Accept:application/json' -H 'Content-Type: application/json' http://localhost:8080/BarcodePayment/transactions/ --data '{"id":5,"amount":5.0,"paid":true}'
Now, I am building a web app using RoR and would like to do something similar. How can I build that? Basically, the RoR web app will be a client that posts to the web service.
Searching SO and the web, I found some helpful links but I cannot get it to work. For example, from this post, he/she uses net/http.
I tried but it doesn't work. In my controller, I have
require 'net/http'
require "uri"
def post_webservice
#transaction = Transaction.find(params[:id])
#transaction.update_attribute(:checkout_started, true);
# do a post service to localhost:8080/BarcodePayment/transactions
# use net/http
url = URI.parse('http://localhost:8080/BarcodePayment/transactions/')
response = Net::HTTP::Post.new(url_path)
request.content_type = 'application/json'
request.body = '{"id":5,"amount":5.0,"paid":true}'
response = Net::HTTP.start(url.host, url.port) {|http| http.request(request) }
assert_equal '201 Created', response.get_fields('Status')[0]
end
It returns with error:
undefined local variable or method `url_path' for #<TransactionsController:0x0000010287ed28>
The sample code I am using is from here
I am not attached to net/http and I don't mind using other tools as long as I can accomplish the same task easily.
Thanks much!
url = URI.parse('http://localhost:8080/BarcodePayment/transactions/')
response = Net::HTTP::Post.new(url_path)
Your problem is exactly what the interpreter told you it is: url_path is undeclared. what you want is to call the #path method on the url variable you declared in the previous line.
url = URI.parse('http://localhost:8080/BarcodePayment/transactions/')
response = Net::HTTP::Post.new(url.path)
should work.

Resources