Browse files

Add ApiException; raised when API response is 4xx or 5xx. Closes #3.

  • Loading branch information...
1 parent d16bab5 commit 43461100de3c11369f060f647edf0d4a6c05ce71 Brandon Tilley committed Jan 30, 2012
View
1 .yardopts
@@ -2,6 +2,7 @@
--markup markdown
--markup-provider redcarpet
--title "Battlenet Documentation"
+--private
lib/**/*.rb
-
README.md
View
4 README.md
@@ -48,10 +48,12 @@ Configuring
Failing Silently
----------------
-By default, if Battlenet receives a non-200 response from the Battle.net API, it will throw an exception. You can turn this behavior off via the `fail_silently` attribute:
+By default, if Battlenet receives a 4xx or 5xx response from the Battle.net API, it will throw a `Battlent::ApiException`. You can turn this behavior off via the `fail_silently` attribute:
Battlenet.fail_silently = true
+The exception will have its `code` attribute set to the HTTP status code returned from the API; if the response included a JSON response with the `reason` field set, the exception will have a `reason` attribute set to this string. You can also access the raw response via the `response` attribute.
+
Localization
------------
View
13 lib/battlenet/battlenet.rb
@@ -1,5 +1,6 @@
require 'httparty'
require 'battlenet/authentication'
+require 'battlenet/exceptions/api_exception'
require 'battlenet/modules/character'
require 'battlenet/modules/guild'
require 'battlenet/modules/realm'
@@ -59,7 +60,7 @@ module Modules; end
include Battlenet::Modules::Data
class << self
- # Whether or not to raise exceptions on non-200 responses from the API endpoint.
+ # Whether or not to raise exceptions on error responses from the API endpoint.
# A value of `false` causes exceptions to be raised. Defaults to `false`.
#
# @return [boolean]
@@ -133,7 +134,8 @@ def fullpath(path)
# @param path [String] the path to GET
# @param params [Hash] options to be turned into query string parameters
# @return [Object] the response object from HTTParty
- # @raise Exception if the response has a non-200 response and `Battlenet.fail_silently` is `false`
+ # @raise Battlenet::ApiException if the response has a 4xx or 5xx response and `Battlenet.fail_silently` is `false`
+ # @see #process_response
# @see http://rubydoc.info/github/jnunemaker/httparty/master/HTTParty/Response
# @private
def make_request(verb, path, params = {})
@@ -158,9 +160,12 @@ def make_request(verb, path, params = {})
end
response = self.class.send(verb, path, options)
+ process_response response
+ end
- if response.code != 200 && Battlenet.fail_silently == false
- raise "Non-200 response: #{response.code}, #{response.body}"
+ def process_response(response)
+ if response.code.to_s =~ /^(4|5)/ && Battlenet.fail_silently == false
+ raise Battlenet::ApiException.new(response)
end
response
end
View
11 lib/battlenet/exceptions/api_exception.rb
@@ -0,0 +1,11 @@
+class Battlenet
+ class ApiException < Exception
+ attr_accessor :response, :code, :reason
+
+ def initialize(response)
+ @response = response
+ @code = response.code
+ @reason = response['reason'] || nil
+ end
+ end
+end
View
26 spec/fixtures/cassettes/not_found.yml
@@ -0,0 +1,26 @@
+---
+- !ruby/struct:VCR::HTTPInteraction
+ request: !ruby/struct:VCR::Request
+ method: :get
+ uri: http://us.battle.net:80/api/wow/item/1234567890
+ body:
+ headers:
+ response: !ruby/struct:VCR::Response
+ status: !ruby/struct:VCR::ResponseStatus
+ code: 404
+ message: Not Found
+ headers:
+ date:
+ - Mon, 30 Jan 2012 18:44:15 GMT
+ server:
+ - Apache
+ x-frame-options:
+ - SAMEORIGIN
+ content-length:
+ - '61'
+ vary:
+ - Accept-Encoding
+ content-type:
+ - application/json;charset=utf-8
+ body: ! '{"status":"nok", "reason": "unable to get item information."}'
+ http_version: '1.1'
View
16 spec/integration/exception_spec.rb
@@ -0,0 +1,16 @@
+require 'spec_helper'
+
+describe Battlenet::ApiException do
+ let(:api) { Battlenet.new }
+
+ it "raises an exception with the reason and code set" do
+ VCR.use_cassette('not_found') do
+ begin
+ item = api.item '1234567890'
+ rescue Battlenet::ApiException => e
+ e.code.should == 404
+ e.reason.should == 'unable to get item information.'
+ end
+ end
+ end
+end
View
18 spec/unit/battlenet_spec.rb
@@ -105,18 +105,28 @@
end
end
- context "when the response does not have a 200 status code" do
+ context "when the response does not have a status code indicating success" do
before(:each) do
- response = mock(:response).as_null_object
- response.should_receive(:code).at_least(:once).and_return(500)
+ response = stub(:response).as_null_object
+ response.stub(:code).and_return(500)
+ response.stub(:[]).with('reason').and_return('Server Error')
Battlenet.should_receive(:get).and_return(response)
end
context "when fail_silently is off" do
it "throws an exception" do
lambda {
api.get '/test'
- }.should raise_error
+ }.should raise_error(Battlenet::ApiException)
+ end
+
+ it "throws an exception with the code and reason set" do
+ begin
+ api.get '/test'
+ rescue Battlenet::ApiException => ex
+ ex.code.should == 500
+ ex.reason.should == 'Server Error'
+ end
end
end
View
23 spec/unit/exceptions/api_exception_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Battlenet::ApiException do
+ let(:response) do
+ resp = stub(:response)
+ resp.stub(:code).and_return(500)
+ resp.stub(:[]).with('reason').and_return('Bad Juju!')
+ resp
+ end
+ let(:ex) { Battlenet::ApiException.new(response) }
+
+ it "gives access to the response" do
+ ex.response.should == response
+ end
+
+ it "has a status code based on the HTTP response code" do
+ ex.code.should == 500
+ end
+
+ it "has a reason based on the response" do
+ ex.reason.should == 'Bad Juju!'
+ end
+end

0 comments on commit 4346110

Please sign in to comment.