HTTP Basic Authentication as default in Ruby HTTP - ruby

Using Ruby 2.2.3 I'm looking for a way to use HTTP Basic Authentication for every request. I know it is possible to define basic_auth per request:
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
request.basic_auth("username", "password")
response = http.request(request)
How can I "globally" use basic_auth?

basic_auth is an instance method of an Net::HTTP object. For convenience you could define a class with the desired basic_auth settings baked-in or given as arguments.
Simple example:
require 'uri'
require 'net/http'
class SimpleHTTP
def initialize uri, user = "default_user", pass = "default_pass"
#uri = URI.parse(uri)
#username = user
#password = pass
end
def request path=nil
#uri.path = path if path # use path if provided
http = Net::HTTP.new(#uri.host, #uri.port)
req = Net::HTTP::Get.new(#uri.request_uri)
req.basic_auth(#username, #password)
http.request(req)
end
end
# Simple Example
http = SimpleHTTP.new('http://www.yoursite.com/defaultpath')
http.request
# Override default user/pass
http2 = SimpleHTTP.new('http://www.yoursite.com/defaultpath', "myusername", "mypass")
http2.request
# Provide path in request method
http = SimpleHTTP.new('http://www.yoursite.com/')
http.request('/some_path')

Related

Trouble passing params into GET request - Ruby script

I have a Ruby script that issues a GET request to a restful API, but it ignores the params that I'm trying to pass in. I want to just get the activated users but it returns all of the users.
Am I not passing in my params correctly? This is my script:
require 'net/http'
require 'net/https'
require 'time'
require 'api-auth'
require 'json'
URL = 'https://<instance name>.mingle-api.thoughtworks.com/api/v2/users.xml'
OPTIONS = {:access_key_id => '<sign in name>', :access_secret_key => '<secret key>'}
PARAMS = {:user => { :activated => true } }
def http_get(url, options={}, params)
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
body = params.to_json
request = Net::HTTP::Get.new(uri.request_uri)
request.body = body
request['Content-Type'] = 'application/json'
request['Content-Length'] = body.bytesize
ApiAuth.sign!(request, options[:access_key_id], options[:access_secret_key])
response = http.request(request)
users = response.body
if response.code.to_i > 300
raise StandardError, <<-ERROR
Request URL: #{url}
Response: #{response.code}
Response Message: #{response.message}
Response Headers: #{response.to_hash.inspect}
Response Body: #{response.body}
ERROR
end
puts users
end
http_get(URL, OPTIONS, PARAMS)
The response is XML of users, formatted like this:
<user>
<id type="integer">2228</id>
<name>NAME</name>
<login>example#example.com</login>
<email>example#example.com</email>
<light type="boolean">false</light>
<icon_path nil="true"></icon_path>
<activated type="boolean">true</activated>
<admin type="boolean">false</admin>
</user>
I'm still a beginner when it comes to coding, so any help is greatly appreciated! Thank you!
You are putting the parameters for the get request in the body, when you should be placing them in the URL, so that the end of the URL looks something like this:
?param1=value1&param2=value2
Use a function like this (source):
require 'uri'
def hash_to_query(hash)
return URI.encode(hash.map{|k,v| "#{k}=#{v}"}.join("&"))
end
When you create the URI:
uri = URI.parse("#{url}?#{hash_to_query(params)}")
Passing the params via the URL did not work for me.
I ended up pulling the data from the XML that was returned instead of narrowing the search. This returns the correct data:
require 'net/http'
require 'net/https'
require 'time'
require 'api-auth'
require 'json'
require 'nokogiri'
URL = 'https://<instance name>.mingle-api.thoughtworks.com/api/v2/users.xml'
OPTIONS = {:access_key_id => '<sign in name>', :access_secret_key => '<secret key>'}
def http_get(url, options={})
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Get.new(uri.request_uri)
ApiAuth.sign!(request, options[:access_key_id], options[:access_secret_key])
response = http.request(request)
users = response.body
if response.code.to_i > 300
raise StandardError, <<-ERROR
Request URL: #{url}
Response: #{response.code}
Response Message: #{response.message}
Response Headers: #{response.to_hash.inspect}
Response Body: #{response.body}
ERROR
end
return users
end
def extract_active_users
all_users = Nokogiri::XML(http_get(URL, OPTIONS))
all_users.search('//user').each do |user|
active_user = user.xpath('activated')
if active_user.text == 'true'
puts user
end
end
end
extract_active_users

URI.parse doesn't want to parse uri with | (pipe) char

I'm trying to send get request with:
require "net/https"
require "uri"
...
uri = "https://graph.facebook.com/v2.2/#{event_id}?access_token=#{access_token}"
uri = URI.parse(uri)
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)
response.body
Facebook sent me an acces_token with | char, and because of it uri = URI.parse(uri) throws an error: URI::InvalidURIError: bad URI(is not URI?) https:/ ....
Is there any other parser, or should I manually extract these host, port, request_uri values? What's the best way of fixing it?
access_token looks like 141112112181111|9Alz3xW7P0CQ_DRomJN2oMeiwXs
event_id is for example 385101904985590
edit: just realized that it's structure is APP_ID|some_token
Have you tried encoding the URI with URI#encode?
uri = 'http://foobar.com?foo=something|weird'
uri = URI.encode(uri)
uri = URI.parse(uri) => #<URI::HTTP:0x007fe2f48775b0 URL:http://foobar.com?foo=something%7Cweird>
Don't try to inject variables into URI query parameters, especially tokens and keys and such as that's a good route to creating an invalid one. Instead, rely on the URI class and let it handle as much as possible.
require 'uri'
event_id = 1
access_token = 'foo|bar'
uri = URI.parse("https://graph.facebook.com/v2.2/#{event_id}")
uri.query = URI.encode_www_form(['access_token', access_token])
uri.to_s # => "https://graph.facebook.com/v2.2/1?access_token&foo%7Cbar"
If you want something more full-featured, Addressable::URI is very nice.
See "Parsing string to add to URL-encoded URL" for more information.

POST request with Ruby and Calabash

I use Calabsh to test iOS app. Duringtest I need to create POST request to change some values and then verify that changes are reflected in UI.
Request looks like:
wwww.testserver.com/userAddMoney?user_id=1&amount=999
To authorize on server I need to pass special parameters to Header of request:
Headers: X-Testing-Auth-Secret: kI7wGju76kjhJHGklk76
require 'net/http'
uri = URI.parse('http://www.testserver.com/userAddMoney?user_id=1&amount=999')
http = Net::HTTP.new(uri.host,uri.port)
## https.use_ssl = true # use https, need require net/https
req = Net::HTTP::Post.new(uri.path)
req['X-Testing-Auth-Secret'] = 'kI7wGju76kjhJHGklk76'
res = http.request(req)
Docs here: Net::HTTP::Post Net::HTTPSession

Sending http post request in Ruby by Net::HTTP

I'm sending a request with custom headers to a web service.
require 'uri'
require 'net/http'
uri = URI("https://api.site.com/api.dll")
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
headers =
{
'HEADER1' => "VALUE1",
'HEADER2' => "HEADER2"
}
response = https.post(uri.path, headers)
puts response
It's not working, I'm receiving an error of:
/usr/lib/ruby/1.9.1/net/http.rb:1932:in `send_request_with_body': undefined method `bytesize' for #<Hash:0x00000001b93a10> (NoMethodError)
How do I solve this?
P.S. Ruby 1.9.3
Try this:
For detailed documentation, take a look at:
http://www.rubyinside.com/nethttp-cheat-sheet-2940.html
require 'uri'
require 'net/http'
uri = URI('https://api.site.com/api.dll')
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
request = Net::HTTP::Post.new(uri.path)
request['HEADER1'] = 'VALUE1'
request['HEADER2'] = 'VALUE2'
response = https.request(request)
puts response
The second argument of Net::HTTP#post needs to be a String containing the data to post (often form data), the headers would be in the optional third argument.
As qqx mentioned, the second argument of Net::HTTP#post needs to be a String
Luckily there's a neat function that converts a hash into the required string:
response = https.post(uri.path, URI.encode_www_form(headers))

Ruby send JSON request

How do I send a JSON request in ruby? I have a JSON object but I dont think I can just do .send. Do I have to have javascript send the form?
Or can I use the net/http class in ruby?
With header - content type = json and body the json object?
uri = URI('https://myapp.com/api/v1/resource')
body = { param1: 'some value', param2: 'some other value' }
headers = { 'Content-Type': 'application/json' }
response = Net::HTTP.post(uri, body.to_json, headers)
require 'net/http'
require 'json'
def create_agent
uri = URI('http://api.nsa.gov:1337/agent')
http = Net::HTTP.new(uri.host, uri.port)
req = Net::HTTP::Post.new(uri.path, 'Content-Type' => 'application/json')
req.body = {name: 'John Doe', role: 'agent'}.to_json
res = http.request(req)
puts "response #{res.body}"
rescue => e
puts "failed #{e}"
end
HTTParty makes this a bit easier I think (and works with nested json etc, which didn't seem to work in other examples I've seen.
require 'httparty'
HTTParty.post("http://localhost:3000/api/v1/users", body: {user: {email: 'user1#example.com', password: 'secret'}}).body
This works on ruby 2.4 HTTPS Post with JSON object and the response body written out.
require 'net/http' #net/https does not have to be required anymore
require 'json'
require 'uri'
uri = URI('https://your.secure-url.com')
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
request.body = {parameter: 'value'}.to_json
response = http.request request # Net::HTTPResponse object
puts "response #{response.body}"
end
real life example, notify Airbrake API about new deployment via NetHttps
require 'uri'
require 'net/https'
require 'json'
class MakeHttpsRequest
def call(url, hash_json)
uri = URI.parse(url)
req = Net::HTTP::Post.new(uri.to_s)
req.body = hash_json.to_json
req['Content-Type'] = 'application/json'
# ... set more request headers
response = https(uri).request(req)
response.body
end
private
def https(uri)
Net::HTTP.new(uri.host, uri.port).tap do |http|
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
end
end
project_id = 'yyyyyy'
project_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
url = "https://airbrake.io/api/v4/projects/#{project_id}/deploys?key=#{project_key}"
body_hash = {
"environment":"production",
"username":"tomas",
"repository":"https://github.com/equivalent/scrapbook2",
"revision":"live-20160905_0001",
"version":"v2.0"
}
puts MakeHttpsRequest.new.call(url, body_hash)
Notes:
in case you doing authentication via Authorisation header set header req['Authorization'] = "Token xxxxxxxxxxxx" or http://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Token.html
A simple json POST request example for those that need it even simpler than what Tom is linking to:
require 'net/http'
uri = URI.parse("http://www.example.com/search.json")
response = Net::HTTP.post_form(uri, {"search" => "Berlin"})
I like this light weight http request client called `unirest'
gem install unirest
usage:
response = Unirest.post "http://httpbin.org/post",
headers:{ "Accept" => "application/json" },
parameters:{ :age => 23, :foo => "bar" }
response.code # Status code
response.headers # Response headers
response.body # Parsed body
response.raw_body # Unparsed body
It's 2020 - nobody should be using Net::HTTP any more and all answers seem to be saying so, use a more high level gem such as Faraday - Github
That said, what I like to do is a wrapper around the HTTP api call,something that's called like
rv = Transporter::FaradayHttp[url, options]
because this allows me to fake HTTP calls without additional dependencies, ie:
if InfoSig.env?(:test) && !(url.to_s =~ /localhost/)
response_body = FakerForTests[url: url, options: options]
else
conn = Faraday::Connection.new url, connection_options
Where the faker looks something like this
I know there are HTTP mocking/stubbing frameworks, but at least when I researched last time they didn't allow me to validate requests efficiently and they were just for HTTP, not for example for raw TCP exchanges, this system allows me to have a unified framework for all API communication.
Assuming you just want to quick&dirty convert a hash to json, send the json to a remote host to test an API and parse response to ruby this is probably fastest way without involving additional gems:
JSON.load `curl -H 'Content-Type:application/json' -H 'Accept:application/json' -X POST localhost:3000/simple_api -d '#{message.to_json}'`
Hopefully this goes without saying, but don't use this in production.
The net/http api can be tough to use.
require "net/http"
uri = URI.parse(uri)
Net::HTTP.new(uri.host, uri.port).start do |client|
request = Net::HTTP::Post.new(uri.path)
request.body = "{}"
request["Content-Type"] = "application/json"
client.request(request)
end
data = {a: {b: [1, 2]}}.to_json
uri = URI 'https://myapp.com/api/v1/resource'
https = Net::HTTP.new uri.host, uri.port
https.use_ssl = true
https.post2 uri.path, data, 'Content-Type' => 'application/json'
Using my favourite http request library in ruby:
resp = HTTP.timeout(connect: 15, read: 30).accept(:json).get('https://units.d8u.us/money/1/USD/GBP/', json: {iAmOne: 'Hash'}).parse
resp.class
=> Hash

Resources