Skip to content

Commit

Permalink
retry on retryable errors (500s and ConnectionError)
Browse files Browse the repository at this point in the history
* retry on retryable errors (500s and ConnectionError)

* remove Gemfile.lock
  • Loading branch information
webandtech committed Aug 9, 2017
1 parent 1fcaddf commit 4bab854
Show file tree
Hide file tree
Showing 13 changed files with 190 additions and 169 deletions.
96 changes: 0 additions & 96 deletions Gemfile.lock

This file was deleted.

5 changes: 3 additions & 2 deletions lib/frederick_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@

# FrederickAPI libs
require 'frederick_api/configuration'
require 'frederick_api/v2/paginator'
require 'frederick_api/v2/query_builder'
require 'frederick_api/v2/helpers/paginator'
require 'frederick_api/v2/helpers/query_builder'
require 'frederick_api/v2/helpers/requestor'
require 'frederick_api/v2/resource'

require 'frederick_api/v2/user'
Expand Down
31 changes: 31 additions & 0 deletions lib/frederick_api/v2/helpers/paginator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module FrederickAPI
module V2
module Helpers
# Custom paginator for json api client
# Fixes param names for pagination
# Also adds ability to get all records from a paginated API
class Paginator < JsonApiClient::Paginating::Paginator
self.page_param = 'page.number'
self.per_page_param = 'page.size'

def all_records
current_result_set = nil
results = self.result_set.to_a
first_resource = self.result_set.first

(total_pages - current_page).times do
first_resource.class.with_headers(first_resource.custom_headers) do
current_result_set = current_result_set ? current_result_set.pages.next : self.result_set.pages.next
raise 'next link not found' unless current_result_set
results.push(*current_result_set.to_a)
end
end

results
end
end
end
end
end
37 changes: 37 additions & 0 deletions lib/frederick_api/v2/helpers/query_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

require 'active_support/core_ext/module'

module FrederickAPI
module V2
module Helpers
# Used to convert nested params to dot notation for Frederick API
class QueryBuilder < JsonApiClient::Query::Builder
def params
to_dot_params(
filter_params.merge(pagination_params.merge(includes_params).merge(select_params))
).merge(order_params)
.merge(primary_key_params)
.merge(path_params)
.merge(additional_params)
end

def to_dot_params(object, prefix = nil)
return {} if object == {}

if object.is_a? Hash
object.map do |key, value|
if prefix
to_dot_params value, "#{prefix}.#{key}"
else
to_dot_params value, key.to_s
end
end.reduce(&:merge)
else
{ prefix => object }
end
end
end
end
end
end
18 changes: 18 additions & 0 deletions lib/frederick_api/v2/helpers/requestor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module FrederickAPI
module V2
module Helpers
# Requestor for v2 client to use built on top of JsonApiClient::Query::Requestor
class Requestor < JsonApiClient::Query::Requestor
# Retry once on unhandled server errors
def request(type, path, params)
super
rescue JsonApiClient::Errors::ConnectionError, JsonApiClient::Errors::ServerError => ex
raise ex if ex.is_a?(JsonApiClient::Errors::NotFound) || ex.is_a?(JsonApiClient::Errors::Conflict)
super
end
end
end
end
end
29 changes: 0 additions & 29 deletions lib/frederick_api/v2/paginator.rb

This file was deleted.

35 changes: 0 additions & 35 deletions lib/frederick_api/v2/query_builder.rb

This file was deleted.

5 changes: 3 additions & 2 deletions lib/frederick_api/v2/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ module V2
# Class from which Frederick V2 Resources inherit
# Inherits functionality from JsonApiClient::Resource
class Resource < JsonApiClient::Resource
self.query_builder = FrederickAPI::V2::QueryBuilder
self.paginator = FrederickAPI::V2::Paginator
self.query_builder = FrederickAPI::V2::Helpers::QueryBuilder
self.paginator = FrederickAPI::V2::Helpers::Paginator
self.requestor_class = FrederickAPI::V2::Helpers::Requestor

attr_accessor :custom_headers

Expand Down
2 changes: 1 addition & 1 deletion lib/frederick_api/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

module FrederickAPI
# Current gem version
VERSION = '0.1.4'
VERSION = '0.1.5'
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require 'spec_helper'

describe FrederickAPI::V2::Paginator do
describe FrederickAPI::V2::Helpers::Paginator do
let(:data) { {} }
let(:first_result) { FrederickAPI::V2::Resource.new }
let(:result) { [first_result, 'b'] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require 'spec_helper'

RSpec.describe FrederickAPI::V2::QueryBuilder do
RSpec.describe FrederickAPI::V2::Helpers::QueryBuilder do
let(:query_builder) { described_class.new('klass') }

describe '#params' do
Expand Down
81 changes: 81 additions & 0 deletions spec/frederick_api/v2/helpers/requestor_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# frozen_string_literal: true

require 'spec_helper'

describe FrederickAPI::V2::Helpers::Requestor do
let(:superklass) { JsonApiClient::Query::Requestor }
let(:requestor) { described_class.new(String) }

it 'has right superclass' do
expect(described_class.superclass).to eq superklass
end

describe '#request' do
let(:error) {}
let(:type) { 'type' }
let(:path) { 'path' }
let(:param) { 'param' }
let(:request_args) { [type, path, param] }
let(:super_instance) { superklass.new(String) }
let(:super_request_call_args) { [] }
let(:request_return) { 'request_return' }

before do
allow_any_instance_of(superklass).to receive(:request) do |*args|
super_request_call_args << args[1..-1]
raise(error) if super_request_call_args.length == 1 && error
request_return
end
end

it 'calls request only once if there is no error' do
expect(requestor.send(:request, *request_args)).to eq request_return
expect(super_request_call_args).to eq [request_args]
end

context 'JsonApiClient::Errors::ServerError' do
let(:error) { JsonApiClient::Errors::ServerError.new('foo') }

it 'calls request twice' do
expect(requestor.send(:request, *request_args)).to eq request_return
expect(super_request_call_args).to eq [request_args, request_args]
end
end

context 'JsonApiClient::Errors::ConnectionError' do
let(:error) { JsonApiClient::Errors::ConnectionError.new('foo') }

it 'calls request twice' do
expect(requestor.send(:request, *request_args)).to eq request_return
expect(super_request_call_args).to eq [request_args, request_args]
end
end

context 'JsonApiClient::Errors::NotFound' do
let(:error) { JsonApiClient::Errors::NotFound.new('foo') }

it 'calls request only once, and does not rescue error' do
expect { requestor.send(:request, *request_args) }.to raise_error error
expect(super_request_call_args).to eq [request_args]
end
end

context 'JsonApiClient::Errors::Conflict' do
let(:error) { JsonApiClient::Errors::Conflict.new('foo') }

it 'calls request only once, and does not rescue error' do
expect { requestor.send(:request, *request_args) }.to raise_error error
expect(super_request_call_args).to eq [request_args]
end
end

context 'other error raised' do
let(:error) { StandardError.new('foo') }

it 'calls request only once, and does not rescue error' do
expect { requestor.send(:request, *request_args) }.to raise_error error
expect(super_request_call_args).to eq [request_args]
end
end
end
end
Loading

0 comments on commit 4bab854

Please sign in to comment.