mirror of
https://github.com/samsonjs/instapaper.git
synced 2026-03-25 08:55:49 +00:00
reimplement error handling
This commit is contained in:
parent
de1196717d
commit
c078efccdf
3 changed files with 139 additions and 56 deletions
|
|
@ -4,40 +4,69 @@ module Instapaper
|
|||
# @return [Integer]
|
||||
attr_reader :code
|
||||
|
||||
# RateLimitExceeded = Class.new(self)
|
||||
# PremiumAccountRequired = Class.new(self)
|
||||
# SuspendedApplication = Class.new(self)
|
||||
#
|
||||
# # 1040: Rate-limit exceeded
|
||||
# # 1041: Premium account required
|
||||
# # 1042: Application is suspended
|
||||
#
|
||||
# BookmarkError = Class.new(self)
|
||||
#
|
||||
# Bookmark errors:
|
||||
#
|
||||
# 1220: Domain requires full content to be supplied
|
||||
# 1221: Domain has opted out of Instapaper compatibility
|
||||
# 1240: Invalid URL specified
|
||||
# 1241: Invalid or missing bookmark_id
|
||||
# 1242: Invalid or missing folder_id
|
||||
# 1243: Invalid or missing progress
|
||||
# 1244: Invalid or missing progress_timestamp
|
||||
# 1245: Private bookmarks require supplied content
|
||||
# 1250: Unexpected error when saving bookmark
|
||||
# Folder errors:
|
||||
#
|
||||
# 1250: Invalid or missing title
|
||||
# 1251: User already has a folder with this title
|
||||
# 1252: Cannot add bookmarks to this folder
|
||||
# Operational errors:
|
||||
#
|
||||
# 1500: Unexpected service error
|
||||
# 1550: Error generating text version of this URL
|
||||
# Highlight Errors:
|
||||
#
|
||||
# 1600: Cannot create highlight with empty text
|
||||
# 1601: Duplicate highlight
|
||||
BookmarkError = Class.new(self)
|
||||
FolderError = Class.new(self)
|
||||
HighlightError = Class.new(self)
|
||||
|
||||
ERRORS = {
|
||||
1040 => 'Rate-limit exceeded',
|
||||
1041 => 'Premium account required',
|
||||
1042 => 'Application is suspended',
|
||||
1500 => 'Unexpected service error',
|
||||
1550 => 'Error generating text version of this URL',
|
||||
}
|
||||
|
||||
BOOKMARK_ERRORS = {
|
||||
1220 => 'Domain requires full content to be supplied',
|
||||
1221 => 'Domain has opted out of Instapaper compatibility',
|
||||
1240 => 'Invalid URL specified',
|
||||
1241 => 'Invalid or missing bookmark_id',
|
||||
1242 => 'Invalid or missing folder_id',
|
||||
1243 => 'Invalid or missing progress',
|
||||
1244 => 'Invalid or missing progress_timestamp',
|
||||
1245 => 'Private bookmarks require supplied content',
|
||||
1250 => 'Unexpected error when saving bookmark',
|
||||
}
|
||||
|
||||
FOLDER_ERRORS = {
|
||||
1250 => 'Invalid or missing title',
|
||||
1251 => 'User already has a folder with this title',
|
||||
1252 => 'Cannot add bookmarks to this folder',
|
||||
}
|
||||
|
||||
HIGHLIGHT_ERRORS = {
|
||||
1600 => 'Cannot create highlight with empty text',
|
||||
1601 => 'Duplicate highlight',
|
||||
}
|
||||
|
||||
CODES = [
|
||||
ERRORS,
|
||||
BOOKMARK_ERRORS,
|
||||
FOLDER_ERRORS,
|
||||
HIGHLIGHT_ERRORS,
|
||||
].collect { |e| e.keys }.flatten
|
||||
|
||||
# Create a new error from an HTTP response
|
||||
#
|
||||
# @param response [HTTP::Response]
|
||||
# @return [Instapaper::Error]
|
||||
def self.from_response(code, path)
|
||||
case path
|
||||
when /highlights/ then HighlightError.new(HIGHLIGHT_ERRORS[code], code)
|
||||
when /bookmarks/ then BookmarkError.new(BOOKMARK_ERRORS[code], code)
|
||||
when /folders/ then FolderError.new(FOLDER_ERRORS[code], code)
|
||||
else new(ERRORS[code], code)
|
||||
end
|
||||
end
|
||||
|
||||
# Initializes a new Error object
|
||||
#
|
||||
# @param message [Exception, String]
|
||||
# @param code [Integer]
|
||||
# @return [Instapaper::Error]
|
||||
def initialize(message = '', code = nil)
|
||||
super(message)
|
||||
@code = code
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -39,33 +39,18 @@ module Instapaper
|
|||
@headers = Instapaper::HTTP::Headers.new(@client, @request_method, @uri, @options).request_headers
|
||||
options_key = @request_method == :get ? :params : :form
|
||||
response = ::HTTP.with(@headers).public_send(@request_method, @uri.to_s, options_key => @options)
|
||||
response_body = raw ? response.to_s : symbolize_keys!(response.parse)
|
||||
response_headers = response.headers
|
||||
fail_or_return_response_body(response.code, response_body, response_headers)
|
||||
fail_if_error(response)
|
||||
raw ? response.to_s : symbolize_keys!(response.parse)
|
||||
end
|
||||
|
||||
def fail_or_return_response_body(code, body, headers)
|
||||
error = nil # error(code, body, headers)
|
||||
def fail_if_error(response)
|
||||
error = error(response.code)
|
||||
fail(error) if error
|
||||
body
|
||||
end
|
||||
|
||||
def error(code, body, headers)
|
||||
klass = Instapaper::Error::ERRORS[code]
|
||||
if klass == Instapaper::Error::Forbidden
|
||||
forbidden_error(body, headers)
|
||||
elsif !klass.nil?
|
||||
klass.from_response(body, headers)
|
||||
end
|
||||
end
|
||||
|
||||
def forbidden_error(body, headers)
|
||||
error = Instapaper::Error::Forbidden.from_response(body, headers)
|
||||
klass = Instapaper::Error::FORBIDDEN_MESSAGES[error.message]
|
||||
if klass
|
||||
klass.from_response(body, headers)
|
||||
else
|
||||
error
|
||||
def error(code)
|
||||
if Instapaper::Error::CODES.index(code.to_i)
|
||||
Instapaper::Error.from_response(code, @path)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
69
spec/instapaper/error_spec.rb
Normal file
69
spec/instapaper/error_spec.rb
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Instapaper::Error do
|
||||
before do
|
||||
@client = Instapaper::Client.new(consumer_key: 'CK', consumer_secret: 'CS', access_token: 'AT', access_token_secret: 'AS')
|
||||
end
|
||||
|
||||
describe '#code' do
|
||||
it 'returns the error code' do
|
||||
error = Instapaper::Error.new('execution expired', 123)
|
||||
expect(error.code).to eq(123)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#message' do
|
||||
it 'returns the error message' do
|
||||
error = Instapaper::Error.new('execution expired')
|
||||
expect(error.message).to eq('execution expired')
|
||||
end
|
||||
end
|
||||
|
||||
Instapaper::Error::ERRORS.each do |status, exception|
|
||||
context "when HTTP status is #{status}" do
|
||||
before do
|
||||
stub_post('/api/1/oauth/access_token')
|
||||
.to_return(status: status, body: '', headers: {content_type: 'application/json; charset=utf-8'})
|
||||
end
|
||||
it "raises #{exception}" do
|
||||
expect { @client.token('foo', 'bar') }.to raise_error(Instapaper::Error)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Instapaper::Error::BOOKMARK_ERRORS.each do |status, exception|
|
||||
context "when HTTP status is #{status}" do
|
||||
before do
|
||||
stub_post('/api/1/bookmarks/list')
|
||||
.to_return(status: status, body: '', headers: {content_type: 'application/json; charset=utf-8'})
|
||||
end
|
||||
it "raises #{exception}" do
|
||||
expect { @client.bookmarks }.to raise_error(Instapaper::Error::BookmarkError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Instapaper::Error::FOLDER_ERRORS.each do |status, exception|
|
||||
context "when HTTP status is #{status}" do
|
||||
before do
|
||||
stub_post('/api/1/folders/list')
|
||||
.to_return(status: status, body: '', headers: {content_type: 'application/json; charset=utf-8'})
|
||||
end
|
||||
it "raises #{exception}" do
|
||||
expect { @client.folders }.to raise_error(Instapaper::Error::FolderError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Instapaper::Error::HIGHLIGHT_ERRORS.each do |status, exception|
|
||||
context "when HTTP status is #{status}" do
|
||||
before do
|
||||
stub_post('/api/1.1/bookmarks/123/highlights')
|
||||
.to_return(status: status, body: fixture('highlights_list.json'), headers: {content_type: 'application/json; charset=utf-8'})
|
||||
end
|
||||
it "raises #{exception}" do
|
||||
expect { @client.highlights('123') }.to raise_error(Instapaper::Error::HighlightError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue