Permalink
Browse files

merge daveworth's changes

  • Loading branch information...
amro committed Oct 27, 2011
1 parent 0fe28f1 commit 762c1f7e0b4a5125948ec15788b2eea73b90cd72
Showing with 67 additions and 15 deletions.
  1. +1 −0 .gitignore
  2. +9 −0 README.markdown
  3. +18 −5 lib/gibbon.rb
  4. +39 −10 test/test_gibbon.rb
View
@@ -46,3 +46,4 @@ cache
gems
specifications
Gemfile.lock
+.rvmrc
View
@@ -89,6 +89,15 @@ return value is an Enumerator which loops over the lines returned from the
Export API. This is because the data returned from the Export API is a stream
of JSON objects rather than a single JSON array.
+### Error handling
+
+By default you are expected to handle errors returned by the APIs manually. The
+APIs will return a Hash with two keys "errors", a string containing some textual
+information about the error, and "code", the numeric code of the error.
+
+If you set the `throws_exceptions` boolean attribute for a given instance then
+Gibbon will attempt to intercept the errors and raise an exception.
+
### Notes
As of 0.1.6, gibbon uses ActiveSupport::JSON.decode(). This means code that checked for weird API responses (like "true"
View
@@ -8,11 +8,12 @@ class Gibbon
format :plain
default_timeout 30
- attr_accessor :api_key, :timeout
+ attr_accessor :api_key, :timeout, :throws_exceptions
def initialize(api_key = nil, extra_params = {})
@api_key = api_key || ENV['MC_API_KEY'] || ENV['MAILCHIMP_API_KEY'] || self.class.api_key
@default_params = {:apikey => @api_key}.merge(extra_params)
+ @throws_exceptions = false
end
def api_key=(value)
@@ -40,14 +41,19 @@ def call(method, params = {})
rescue
response = response.body
end
+
+ if @throws_exceptions && response.is_a?(Hash) && response["error"]
+ raise "Error from MailChimp API: #{response["error"]} (code #{response["code"]})"
+ end
+
response
end
def method_missing(method, *args)
method = method.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } #Thanks for the gsub, Rails
method = method[0].chr.downcase + method[1..-1].gsub(/aim$/i, 'AIM')
args = {} unless args.length > 0
- args = args[0] if (args.class.to_s == "Array")
+ args = args[0] if args.is_a?(Array)
call(method, args)
end
@@ -76,10 +82,17 @@ def export_api_url
end
def call(method, params = {})
- url = export_api_url + method + "/"
+ method_params = {:apikey => @api_key, :id => params[:id]}.to_a.map {|a| "#{a[0]}=#{CGI::escape(a[1])}"}.join("&")
+ url = export_api_url + method + "?" + method_params
params = @default_params.merge(params)
- response = self.class.post(url, :body => params, :timeout => @timeout)
+ response = self.class.post(url, :body => CGI::escape(params.to_json), :timeout => @timeout)
+
+ lines = response.body.lines
+ if @throws_exceptions
+ first_line_object = ActiveSupport::JSON.decode(lines.peek) if lines.peek
+ raise "Error from MailChimp Export API: #{first_line_object["error"]} (code #{first_line_object["code"]})" if first_line_object.is_a?(Hash) && first_line_object["error"]
+ end
- response.body.lines
+ lines
end
end
View
@@ -121,40 +121,69 @@ class TestGibbon < Test::Unit::TestCase
@gibbon = Gibbon.new(@key)
@url = "https://us1.api.mailchimp.com/1.3/?method=sayHello"
@body = {"apikey" => @key}
+ @returns = Struct.new(:body).new(ActiveSupport::JSON.encode(["array", "entries"]))
end
should "produce a good exporter" do
@exporter = @gibbon.get_exporter
assert_equal(@exporter.api_key, @gibbon.api_key)
end
+
+ should "throw exception if configured to and the API replies with a JSON hash containing a key called 'error'" do
+ Gibbon.stubs(:post).returns(Struct.new(:body).new(ActiveSupport::JSON.encode({'error' => 'bad things'})))
+ assert_nothing_raised do
+ result = @gibbon.say_hello
+ end
+
+ ap result
+ end
+
+ should "throw exception if configured to and the API replies with a JSON hash containing a key called 'error'" do
+ @gibbon.throws_exceptions = true
+ Gibbon.stubs(:post).returns(Struct.new(:body).new(ActiveSupport::JSON.encode({'error' => 'bad things'})))
+ assert_raise RuntimeError do
+ @gibbon.say_hello
+ end
+ end
end
context "export API" do
setup do
@key = "TESTKEY-us1"
@gibbon = GibbonExport.new(@key)
@url = "http://us1.api.mailchimp.com/export/1.0/"
- @body = {:apikey => @key}
- @returns = Struct.new(:body).new("")
+ @body = {:apikey => @key, :id => "listid"}
+ @returns = Struct.new(:body).new(ActiveSupport::JSON.encode(["array", "entries"]))
end
should "handle api key with dc" do
@api_key = "TESTKEY-us2"
@gibbon = GibbonExport.new(@api_key)
- params = {:body => {:apikey => @api_key}, :timeout => nil}
- url = @url.gsub('us1', 'us2') + "sayHello/"
+ params = {:body => CGI::escape(@body.to_json), :timeout => nil}
+ url = @url.gsub('us1', 'us2') + "sayHello?apikey=TESTKEY-us2&id=listid"
GibbonExport.expects(:post).with(url, params).returns(@returns)
- @gibbon.say_hello
+ @gibbon.say_hello(@body)
end
- should "not escape string parameters" do
- @param = "list id"
+ should "not throw exception if the Export API replies with a JSON hash containing a key called 'error'" do
+ GibbonExport.stubs(:post).returns(Struct.new(:body).new(ActiveSupport::JSON.encode({'error' => 'bad things'})))
- params = {:body => @body.merge(:id => 'list id'), :timeout => nil}
- GibbonExport.expects(:post).with(@url + 'sayHello/', params).returns(@returns)
- @gibbon.say_hello(:id => @param)
+ assert_nothing_raised do
+ @gibbon.say_hello(@body)
+ end
end
+
+ should "throw exception if configured to and the Export API replies with a JSON hash containing a key called 'error'" do
+ @gibbon.throws_exceptions = true
+ params = {:body => @body, :timeout => nil}
+ GibbonExport.stubs(:post).returns(Struct.new(:body).new(ActiveSupport::JSON.encode({'error' => 'bad things', 'code' => '123'})))
+
+ assert_raise RuntimeError do
+ @gibbon.say_hello(@body)
+ end
+ end
+
end
private

0 comments on commit 762c1f7

Please sign in to comment.