From 8ab35f58ea369e9c3ac19976264afd69ec508be2 Mon Sep 17 00:00:00 2001 From: nov Date: Wed, 11 Jun 2014 17:45:05 +0900 Subject: [PATCH] better exception handling --- lib/fb_graph2/app_link_host.rb | 2 - lib/fb_graph2/exception.rb | 81 ++++++++++++++++++++++++++++++++++ lib/fb_graph2/node.rb | 6 +-- spec/fb_graph2/node_spec.rb | 8 ++-- spec/spec_helper/mock_graph.rb | 5 ++- 5 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 lib/fb_graph2/exception.rb diff --git a/lib/fb_graph2/app_link_host.rb b/lib/fb_graph2/app_link_host.rb index 286a922..cfd6dfa 100644 --- a/lib/fb_graph2/app_link_host.rb +++ b/lib/fb_graph2/app_link_host.rb @@ -25,8 +25,6 @@ module FbGraph2 Struct::AppLink::Native::Android when :windows_phone Struct::AppLink::Native::WindowsPhone - else - raise 'Unknown AppLink Type' end klass.new link end diff --git a/lib/fb_graph2/exception.rb b/lib/fb_graph2/exception.rb new file mode 100644 index 0000000..4981fcc --- /dev/null +++ b/lib/fb_graph2/exception.rb @@ -0,0 +1,81 @@ +module FbGraph2 + class Exception < StandardError + attr_accessor :status, :type, :code + + class << self + def detect(status, body = {}, headers = {}) + error = body[:error] + message = error.try(:[], :message) + klass = detect_from_header(headers, error) || detect_from_status(status) + if klass + klass.new message, error + else + new status, message, error + end + end + + def detect_from_status(status) + case status + when 400 + BadRequest + when 401 + Unauthorized + when 404 + NotFound + when 500 + InternalServerError + end + end + + def detect_from_header(headers, error) + key, value = headers.detect do |name, value| + name.upcase == "WWW-Authenticate".upcase + end || return + matched, klass = ERROR_HEADER_MATCHERS.detect do |matcher, klass_name| + matcher =~ value + end || return + klass + end + end + + def initialize(status, message, error = {}) + super message + self.status = status + self.type = error[:type] + self.code = error[:code] + end + + class BadRequest < Exception + def initialize(message, details = {}) + super 400, message, details + end + end + + class Unauthorized < Exception + def initialize(message, details = {}) + super 401, message, details + end + end + + class NotFound < Exception + def initialize(message, details = {}) + super 404, message, details + end + end + + class InternalServerError < Exception + def initialize(message, details = {}) + super 500, message, details + end + end + + class InvalidToken < Unauthorized; end + class InvalidRequest < BadRequest; end + + ERROR_HEADER_MATCHERS = { + /not_found/ => NotFound, + /invalid_token/ => InvalidToken, + /invalid_request/ => InvalidRequest + } + end +end \ No newline at end of file diff --git a/lib/fb_graph2/node.rb b/lib/fb_graph2/node.rb index 412a9eb..f0bcbc2 100644 --- a/lib/fb_graph2/node.rb +++ b/lib/fb_graph2/node.rb @@ -107,12 +107,10 @@ module FbGraph2 when 200...300 _response_ else - # TODO: better exception structure - raise response.body + raise Exception.detect(response.status, _response_, response.headers) end rescue MultiJson::DecodeError - # TODO: better exception structure - raise response.body + raise Exception.new(response.status, "Unparsable Response: #{response.body}") end end end \ No newline at end of file diff --git a/spec/fb_graph2/node_spec.rb b/spec/fb_graph2/node_spec.rb index e276f5b..2a96845 100644 --- a/spec/fb_graph2/node_spec.rb +++ b/spec/fb_graph2/node_spec.rb @@ -103,8 +103,8 @@ describe FbGraph2::Node do instance.fetch end end.to raise_error { |e| - e.should be_instance_of RuntimeError - e.message.should == mock_json('error/400/2500') + e.should be_instance_of FbGraph2::Exception::BadRequest + e.message.should == mock_json('error/400/2500')[:error][:message] } end end @@ -116,8 +116,8 @@ describe FbGraph2::Node do instance.fetch end end.to raise_error { |e| - e.should be_instance_of RuntimeError - e.message.should == mock_json('error/invalid_format') + e.should be_instance_of FbGraph2::Exception + e.message.should == "Unparsable Response: #{mock_json('error/invalid_format')}" } end end diff --git a/spec/spec_helper/mock_graph.rb b/spec/spec_helper/mock_graph.rb index 7b313e4..9432769 100644 --- a/spec/spec_helper/mock_graph.rb +++ b/spec/spec_helper/mock_graph.rb @@ -23,7 +23,10 @@ module MockGraph end def mock_json(response_path) - response_for(response_path)[:body].read + content = response_for(response_path)[:body].read + MultiJson.load(content).with_indifferent_access + rescue MultiJson::DecodeError + content end def request_to(path, method = :get, options = {})