getoutreach / bullhorn-rest

Ruby wrapper for the Bullhorn REST API
MIT License
11 stars 22 forks source link

'URI': bad argument (expected URI object or URI string) (ArgumentError) #3

Open dannysmith opened 9 years ago

dannysmith commented 9 years ago

Having read #2, I tried installing bullhorn-rest from source, but am getting an error:

/Users/danny/.rbenv/versions/2.1.4/lib/ruby/2.1.0/uri/common.rb:1234:in `URI': bad argument (expected URI object or URI string) (ArgumentError)
    from /Users/danny/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/bundler/gems/bullhorn-rest-8eb5f0648b81/lib/bullhorn/rest/authentication.rb:25:in `authorize'
    from /Users/danny/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/bundler/gems/bullhorn-rest-8eb5f0648b81/lib/bullhorn/rest/authentication.rb:82:in `authenticate'
    from /Users/danny/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/bundler/gems/bullhorn-rest-8eb5f0648b81/lib/bullhorn/rest/authentication.rb:128:in `call'
    from /Users/danny/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/faraday-0.9.0/lib/faraday/rack_builder.rb:139:in `build_response'
    from /Users/danny/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/faraday-0.9.0/lib/faraday/connection.rb:377:in `run_request'
    from /Users/danny/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/faraday-0.9.0/lib/faraday/connection.rb:140:in `get'
    from /Users/danny/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/bundler/gems/bullhorn-rest-8eb5f0648b81/lib/bullhorn/rest/entities/base.rb:61:in `block in define_methods'
    from bullhorn.rb:11:in `<main>'

Here's my code:

# Gemfile
source 'https://rubygems.org'
gem 'hashie'
gem 'bullhorn-rest', git: 'https://github.com/getoutreach/bullhorn-rest.git'
# bullhorn.rb
require 'rubygems'
require 'bundler/setup'
require 'bullhorn/rest'
c = Bullhorn::Rest::Client.new(username: 'xxxI',
                                    password: 'xxx',
                                    client_id: 'xxx',
                                    client_secret: 'xxx')
c.candidates

It's obviously being caused by these lines in authorise.rb (line 25):

res = auth_conn.get url, params
location = res.headers['location']
self.auth_code = CGI::parse(URI(location).query)["code"].first

Presumably location is either nil or not in the correct format. I'll fork and do some more digging.

dannysmith commented 9 years ago

screen shot 2014-12-04 at 14 31 25

It seems that res.headers doesn't contain 'location'.

dannysmith commented 9 years ago

I was able to fix the issue by hitting the API in a browser at https://auth.bullhornstaffing.com/oauth/authorize?action=Login&client_id=XXX&response_type=code&username=XXX without sending the password parameter and manually typing the password.

I've not used the Bullhorn API before, and it looks like this is a required step if that's the case. It might be worth updating the README.

mrmattwright commented 8 years ago

I have seen the same thing, did a bit of digging and testing. If you repeatedly call the bullhorn api you eventually get this error, I think it's probably a race condition on their side

If authorize fails location is almost always set to:

"location"=>
      "http://auth.bullhornstaffing.com/bullhorn-oauth-services-2.0/www.bullhorn.com?error=server_error&error_description=Timer+already+cancelled.",

See the BH forum: https://supportforums.bullhorn.com/viewtopic.php?t=15227 https://supportforums.bullhorn.com/viewtopic.php?t=15597

in my fork of the repo my authorize method now looks like this:

 def authorize
    url = "https://#{self.auth_host}/oauth/authorize"
    params = {
      client_id: client_id,
      username: username,
      password: password,
      action: 'Login',
      response_type: 'code'
    }

    #Note: Sometimes we get a 500 from the server saying "Timer already cancelled".
    #https://supportforums.bullhorn.com/viewtopic.php?t=15227
    #https://supportforums.bullhorn.com/viewtopic.php?t=15597

    #In this case we retry until it works, with a timeout
    Timeout.timeout(30) {
      loop do
        res = auth_conn.get url, params
        location = res.headers['location']
        self.auth_code = CGI::parse(URI(location).query)["code"].first
        break if self.auth_code
      end
    }
  end

I've hit the API pretty hard since adding this and zero errors so far! :)

Will raise a PR against the main repo in case people want that fix.