httparty: how to log request? - ruby

How do I log requests being sent with with httparty?
HTTParty.post(
#application_url,
:headers => {
"Accept" => "application/json",
"Content-Type" => "application/json; charset=utf-8"
},
:body => {
"ApplicationProfileId" => application.applicationProfileId
}.to_json
)

Use debug_output at the class level:
class Foo
include HTTParty
debug_output $stdout
end
or per request
response = HTTParty.post(url, :body => body, :debug_output => $stdout)

You ca use a built-in logger:
my_logger = Rails.logger || Logger.new # use what you like
my_logger.info "The default formatter is :apache. The :curl formatter can also be used."
my_logger.info "You can tell which method to call on the logger too. It is info by default."
HTTParty.get "http://google.com", logger: my_logger, log_level: :debug, log_format: :curl

Use the class-level debug_output method to set an output stream where debugging information gets sent.

Related

Can't mock website with Basic Authentication

Using Ruby, Mechanize, RSpec, and Webmock, I can not mock a website with Basic Authentication, my app keeps telling me that I got an unregistered stub.
The stubs:
stub_request(:get, "http://foo:bar#google.fr:80/").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "", :headers => {})
Net::HTTP.start('www.google.fr') {|http|
req = Net::HTTP::Get.new('/')
req.basic_auth 'foo', 'bar'
http.request(req)
}
In the app:
url = 'http://www.google.fr'
agent = Mechanize.new
agent.add_auth(url, 'foo', 'bar')
agent.get(url)
The issue I get when running agent.get(url)
(rdb:1) agent.get(url)
*** WebMock::NetConnectNotAllowedError Exception: Real HTTP connections are disabled. Unregistered request: GET http://www.google.fr/ with headers {'Accept'=>'*/*', 'Accept-Charset'=>'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Accept-Encoding'=>'gzip,deflate,identity', 'Accept-Language'=>'en-us,en;q=0.5', 'Connection'=>'keep-alive', 'Host'=>'www.google.fr', 'Keep-Alive'=>'300', 'User-Agent'=>'Mechanize/2.7.3 Ruby/1.9.3p194 (http://github.com/sparklemotion/mechanize/)'}
You can stub this request with the following snippet:
stub_request(:get, "http://www.google.fr/").
with(:headers => {'Accept'=>'*/*', 'Accept-Charset'=>'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Accept-Encoding'=>'gzip,deflate,identity', 'Accept-Language'=>'en-us,en;q=0.5', 'Connection'=>'keep-alive', 'Host'=>'www.google.fr', 'Keep-Alive'=>'300', 'User-Agent'=>'Mechanize/2.7.3 Ruby/1.9.3p194 (http://github.com/sparklemotion/mechanize/)'}).
to_return(:status => 200, :body => "", :headers => {})
registered request stubs:
stub_request(:get, "http://foo:bar#www.google.fr/").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'})
A few points:
Assigning 'http://foo:bar#google.fr/' to url does
not work neither (and that would be very ugly if it works anyways).
Last but not least, creating a stub with http://www.google.fr/' as a url would not use basic authentication, since if I do so, even if I change the credentials, I will still access to my mocked page and no errors would be rendered.
Some screenshots:
There exists an incompatibility between WebMock and net-http-persistent.
See https://github.com/bblimke/webmock#connecting-on-nethttpstart
Add WebMock.allow_net_connect!(:net_http_connect_on_start => true) to your test set up.
According to the documentation this should work:
stub_request(:get, "foo:bar#www.google.fr").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "", :headers => {})

How can I use Digest and Basic authentications with HTTParty in the same class?

I have the following class performing some requests:
the first request uses a digest auth
the second request uses a basic auth
When I run the second request I have the following error:
only one authentication method, :basic_auth or :digest_auth may be used at a time
How can I invalidate the digest_auth prior to running the second request?
class Test
include HTTParty
debug_output $stdout
digest_auth 'login', 'pass'
def first_request(href)
self.class.base_uri "SERVER:PORT"
response = self.class.get(href, {:query => {}})
response
end
def second_request(href)
auth = {:username => "USERNAME", :password => "PASSWORD"}
options = { :body => xml_string, :basic_auth => auth }
response = self.class.post('', options)
response
end
end
When you use basic_auth or digest_auth, HTTParty stores the information internally in the #default_options hash. Here is the source for basic_auth:
# File 'lib/httparty.rb', line 102
def basic_auth(u, p)
default_options[:basic_auth] = {:username => u, :password => p}
end
You can get access to that hash using the default_options method:
# File 'lib/httparty.rb', line 452
def default_options #:nodoc:
#default_options
end
I'd try:
default_options.delete(:basic_auth)
or:
default_options.delete(:digest_auth)
prior to using the other authentication method.
This is untested code but looks 'bout right:
class Test
include HTTParty
debug_output $stdout
def first_request(href)
klass = self.class
klass.base_uri "SERVER:PORT"
klass.default_options.delete(:basic_auth)
klass.digest_auth 'login', 'pass'
klass.get(href, {:query => {}})
end
def second_request(href)
klass = self.class
klass.default_options.delete(:digest_auth)
klass.post(
'',
{
:body => xml_string,
:basic_auth => {
:username => "USERNAME",
:password => "PASSWORD"
}
}
)
end
end

How to use WebMock to mock Paperclip call in a Sinatra app?

This code works fine without WebMock.
Raising an exception:
Paperclip::AdapterRegistry::NoHandlerError:
No handler found for #<URI::HTTP:0x007ff3852cefb8 URL:http://www.example.com/images/foo.jpg>
# ./spec/support/api_mock.rb:34:in `process_image_for'
Test:
let( :image_url ) { 'http://www.example.com/images/foo.jpg' }
...
stub_request(:post, image_url)
.to_return(:status => 200, :body => File.read('spec/fixtures/image.jpg'), :headers => {})
...hit Sinatra app...
api_mock.rb:
def self.process_image_for suggestion, params
if params[:image]
suggestion.image = URI.parse( params[:image] ) # line 34
suggestion.save!
end
end
It works. FWIW, both File.read and File.open work:
stub_request(:post, image_url)
.to_return(
:status => 200,
:body => File.read('spec/fixtures/image.jpg'),
:headers => {}
)
Just remember to require 'webmock/rspec' at the top of the test.
it is required to use headers: {"Content-Type" => 'image/jpg'} or any valid content type expected by Paperclip
eg.
stub_request(:get, "http://img.youtube.com/vi/123123123123/0.jpg")
.to_return(
status: 200,
body: File.read('spec/fixtures/images/sample.jpg'),
headers: {"Content-Type" => 'image/jpg'}
)

How do I do basic authentication with RestClient?

Does anyone know how to do basic authentication with RestClient?
I need to create a private repository on GitHub through their RESTful API.
The easiest way is to embed the details in the URL:
RestClient.get "http://username:password#example.com"
Here is an example of working code where I support optional basicauth but don't require the user and password be embedded in the URL:
def get_collection(path)
response = RestClient::Request.new(
:method => :get,
:url => "#{#my_url}/#{path}",
:user => #my_user,
:password => #my_pass,
:headers => { :accept => :json, :content_type => :json }
).execute
results = JSON.parse(response.to_str)
end
Do note if #my_user and #mypass are not instantiated, it works fine without basicauth.
From the source it looks like you can just specify user and password as part of your request object.
Have you tried something like:
r = Request.new({:user => "username", :password => "password"})
Also if you look down in the Shell section of the ReadMe it has an example of specifying it as part of restshell.
$ restclient https://example.com user pass
>> delete '/private/resource'
This works and follows RFC 7617 for Http Basic Authentication:
RestClient::Request.execute(
method: :post,
url: "https://example.com",
headers: { "Authorization" => "Basic " + Base64::encode64(auth_details) },
payload: { "foo" => "bar"}
)
def auth_details
ENV.fetch("HTTP_AUTH_USERNAME") + ":" + ENV.fetch("HTTP_AUTH_PASSWORD")
end
Thanks to Kelsey Hannan:
RestClient.get("https://example.com",
{
Authorization: "Basic #{Base64::encode64('guest:guest')}"
}
)
RestClient.post("https://example.com",
{ }.to_json,
{
Authorization: "Basic #{Base64::encode64('guest:guest')}"
}
)

Can I use rest-client to POST a binary file to HTTP without multipart?

I have tried to do the following, but the web-service is NOT REST and does not take multi-part. What do I do in order to POST the image?
#response = RestClient.post('http://www.postful.com/service/upload',
{:upload => {
:file => File.new("#{#postalcard.postalimage.path}",'rb')
}
},
{"Content-Type" => #postalcard.postalimage.content_type,
"Content-Length" => #postalcard.postalimage.size,
"Authorization" => 'Basic xxxxxx'
} # end headers
) #close arguments to Restclient.post
Got the answer: use I/O to stream as a string instead of using File.new....
:file => IO.read("#{#postalcard.postalimage.path}")

Resources