frederick_api 0.4.3 → 0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 885bbe71573e83a6cd26d1321539c05885b09bf3
4
- data.tar.gz: d8154b394e152ed1b15fa57704cec9588bdb083c
2
+ SHA256:
3
+ metadata.gz: f39d405adb2db91e4cb552498c7188779cba58f587c7d2a35824f0cc18ee4587
4
+ data.tar.gz: 53b2858d0355ac8bba535e75d7950c0407cbfe61317b52f38d4623e002f044e4
5
5
  SHA512:
6
- metadata.gz: '049c7b295aaeed0a069646b36cb66c95a6a4b6e4ccec7807c522e33e6fb0e16358ac3a71841dc3ab97c65f3b25eecfd45bd3277787ffa172fc6ecbe0353438f4'
7
- data.tar.gz: da213d17ac1a57a7b176f8fa3e4e8e43b3d85299f84fb52cadd3c04714cb8d819ce9930867390a4402e7275fdf6ee30bf1866dcbce02a730242c9b9f0ca1b591
6
+ metadata.gz: 65a77c37baa3e8d3f170438d206a3095d21ca3b4548a6f009dd3cb450dcba43453c8f99f8704df0898a631b67dd3595002a7e7723d0c21124b1349869beba5ee
7
+ data.tar.gz: eabcd9f083df57b8b7350a405daa27cdaa8eebe82a00ea65694dbbf03bcbc0e94e0ec7bc2f5fd345106cd4ee30ddd327c31a4c24ca21317ac272b10dc2e4fa98
data/README.md CHANGED
@@ -101,3 +101,14 @@ FrederickAPI::V2::Location.with_access_token(access_token) do
101
101
  # => [...]
102
102
  end
103
103
  ```
104
+ ### Background Jobs
105
+
106
+ FrederickAPI Gem handles asynchronous responses as suggested in
107
+ [JSONApi Recommendations](https://jsonapi.org/recommendations/#asynchronous-processing)
108
+ [Asynchronous Processing](https://jsonapi.org/recommendations/#asynchronous-processing).
109
+ Polling until the job is complete, fetching and returning the completed resource.
110
+
111
+ * A FrederickAPI::V2::Errors::BackgroundJobFailure exception is raised if the API returns
112
+ an error on an asyncronous job.
113
+ * A BackgroundJob Resource will be returned from the client in the case that a successful
114
+ job does not return a resources.
@@ -12,11 +12,13 @@ require 'frederick_api/v2/helpers/has_many'
12
12
  require 'frederick_api/v2/helpers/paginator'
13
13
  require 'frederick_api/v2/helpers/query_builder'
14
14
  require 'frederick_api/v2/helpers/requestor'
15
+ require 'frederick_api/v2/helpers/backgroundable_parser'
15
16
  require 'frederick_api/v2/resource'
16
17
  require 'frederick_api/v2/public_resource'
17
18
 
18
19
  require 'frederick_api/v2/user'
19
20
  require 'frederick_api/v2/location'
21
+ require 'frederick_api/v2/background_job'
20
22
 
21
23
  # Public resources
22
24
  require 'frederick_api/v2/business_category'
@@ -29,6 +31,9 @@ require 'frederick_api/v2/contact_property'
29
31
  require 'frederick_api/v2/contact_list'
30
32
  require 'frederick_api/v2/contact_type'
31
33
  require 'frederick_api/v2/interaction'
34
+ require 'frederick_api/v2/role'
35
+ require 'frederick_api/v2/campaign'
36
+ require 'frederick_api/v2/email_document'
32
37
 
33
38
  # Namespace for all Frederick API client methods/classes
34
39
  module FrederickAPI
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ # V2 Frederick API async background job class for parsing
6
+ # background job responses coming from API.
7
+ class BackgroundJob < Resource
8
+ attr_accessor :response
9
+
10
+ def has_errors?
11
+ @attributes['status'] == 'error'
12
+ end
13
+
14
+ def retry_after
15
+ try_time = @response[:headers]['retry-after'].to_i
16
+ @retry_after ||= try_time > 1 ? try_time : 1
17
+ end
18
+
19
+ def response_code
20
+ @response_code ||= @response[:status]
21
+ end
22
+
23
+ def status
24
+ @attributes['status']
25
+ end
26
+
27
+ def errors
28
+ @attributes['messages']
29
+ end
30
+
31
+ def id
32
+ @attributes['id']
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ # V2 Campaign Resource
6
+ class Campaign < Resource
7
+ belongs_to :location
8
+
9
+ self.read_only_attributes += [:location_id]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ # V2 Email Document Resource
6
+ class EmailDocument < Resource
7
+ belongs_to :location
8
+
9
+ self.read_only_attributes += [:location_id]
10
+ end
11
+ end
12
+ end
@@ -23,6 +23,10 @@ module FrederickAPI
23
23
  class BadRequest < Error; end
24
24
  class UnprocessableEntity < Error; end
25
25
 
26
+ # an exception class for when the server reports that a
27
+ # long running job has failed.
28
+ class BackgroundJobFailure < Error; end
29
+
26
30
  ERROR_CODES = {
27
31
  '400' => BadRequest,
28
32
  '422' => UnprocessableEntity
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ module Helpers
6
+ # Custom Parser for parsing BackgroundJob resources for FrederickAPI V2
7
+ class BackgroundableParser < ::JsonApiClient::Parsers::Parser
8
+ def self.parse(klass, response)
9
+ result_set = super(klass, response)
10
+ return result_set unless result_set&.first&.type == 'background_jobs'
11
+ result_set = super(::FrederickAPI::V2::BackgroundJob, response)
12
+ result_set&.first&.response = { headers: response.headers, status: response.status }
13
+ result_set
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -20,7 +20,7 @@ module FrederickAPI
20
20
  def query_builder(url)
21
21
  association_class.query_builder.new(
22
22
  association_class,
23
- association_class.requestor_class.new(association_class, url)
23
+ requestor: association_class.requestor_class.new(association_class, url)
24
24
  )
25
25
  end
26
26
 
@@ -9,9 +9,9 @@ module FrederickAPI
9
9
  class QueryBuilder < JsonApiClient::Query::Builder
10
10
  attr_reader :requestor
11
11
 
12
- def initialize(klass, requestor = nil)
13
- super(klass)
14
- @requestor = requestor || klass.requestor
12
+ def initialize(klass, opts = {})
13
+ super(klass, opts)
14
+ @requestor = opts[:requestor] || klass.requestor
15
15
  end
16
16
 
17
17
  def params
@@ -23,17 +23,6 @@ module FrederickAPI
23
23
  .merge(additional_params)
24
24
  end
25
25
 
26
- def find(args = {})
27
- case args
28
- when Hash
29
- where(args)
30
- else
31
- @primary_key = args
32
- end
33
-
34
- requestor.get(params)
35
- end
36
-
37
26
  def filter_params
38
27
  super_filter_params = super
39
28
 
@@ -65,6 +54,27 @@ module FrederickAPI
65
54
  { prefix => object }
66
55
  end
67
56
  end
57
+
58
+ protected
59
+
60
+ def _fetch
61
+ (requestor || klass.requestor).get(params)
62
+ end
63
+
64
+ private
65
+
66
+ def _new_scope(opts = {})
67
+ self.class.new(@klass,
68
+ requestor: requestor,
69
+ primary_key: opts.fetch(:primary_key, @primary_key),
70
+ pagination_params: @pagination_params.merge(opts.fetch(:pagination_params, {})),
71
+ path_params: @path_params.merge(opts.fetch(:path_params, {})),
72
+ additional_params: @additional_params.merge(opts.fetch(:additional_params, {})),
73
+ filters: @filters.merge(opts.fetch(:filters, {})),
74
+ includes: @includes + opts.fetch(:includes, []),
75
+ orders: @orders + opts.fetch(:orders, []),
76
+ fields: @fields + opts.fetch(:fields, []))
77
+ end
68
78
  end
69
79
  end
70
80
  end
@@ -7,6 +7,24 @@ module FrederickAPI
7
7
  class Requestor < JsonApiClient::Query::Requestor
8
8
  attr_reader :path
9
9
 
10
+ # For backward compatibility, preserve these JSON API client errors instead of raising
11
+ # FrederickAPI::Errors::Error
12
+ JSON_API_CLIENT_PASSTHROUGH_ERRORS = [
13
+ JsonApiClient::Errors::NotAuthorized,
14
+ JsonApiClient::Errors::AccessDenied,
15
+ JsonApiClient::Errors::NotFound,
16
+ JsonApiClient::Errors::Conflict,
17
+ JsonApiClient::Errors::ServerError,
18
+ JsonApiClient::Errors::UnexpectedStatus
19
+ ].freeze
20
+
21
+ # Paths that may have an unbounded query param length so we should always use a POST
22
+ # instead of a GET to get around AWS Cloudfront limitations
23
+ GET_VIA_POST_PATHS = [
24
+ %r{^.*locations\/[^\/]+\/contacts$},
25
+ %r{^.*locations\/[^\/]+\/interactions$}
26
+ ].map(&:freeze).freeze
27
+
10
28
  def initialize(klass, path = nil)
11
29
  @klass = klass
12
30
  @path = path
@@ -21,15 +39,49 @@ module FrederickAPI
21
39
  end
22
40
  end
23
41
 
42
+ def get(params = {})
43
+ path = resource_path(params)
44
+
45
+ params.delete(klass.primary_key)
46
+ if get_via_post_path?(path)
47
+ return request(:post, path, body: params.to_json, additional_headers: { 'X-Request-Method' => 'GET' })
48
+ end
49
+
50
+ request(:get, path, params: params)
51
+ end
52
+
53
+ def linked(path)
54
+ uri = URI.parse(path)
55
+ return super unless get_via_post_path?(uri.path)
56
+
57
+ path_without_params = "#{uri.scheme}://#{uri.host}#{uri.path}"
58
+ params = uri.query ? CGI.parse(uri.query).each_with_object({}) { |(k, v), h| h[k] = v[0] } : {}
59
+ request(:post, path_without_params, params: params, additional_headers: { 'X-Request-Method' => 'GET' })
60
+ end
61
+
24
62
  # Retry once on unhandled server errors
25
- def request(type, path, params)
26
- handle_errors(super)
27
- rescue JsonApiClient::Errors::ConnectionError, JsonApiClient::Errors::ServerError => ex
28
- raise ex if ex.is_a?(JsonApiClient::Errors::NotFound) || ex.is_a?(JsonApiClient::Errors::Conflict)
29
- handle_errors(super)
63
+ def request(type, path, params: nil, body: nil, additional_headers: {})
64
+ headers = klass.custom_headers.merge(additional_headers)
65
+ make_request = proc do
66
+ handle_background(handle_errors(make_request(type, path, params: params, body: body, headers: headers)))
67
+ end
68
+
69
+ begin
70
+ make_request.call
71
+ rescue JsonApiClient::Errors::ConnectionError, JsonApiClient::Errors::ServerError => ex
72
+ raise ex if ex.is_a?(JsonApiClient::Errors::NotFound) || ex.is_a?(JsonApiClient::Errors::Conflict)
73
+ make_request.call
74
+ end
30
75
  end
31
76
 
32
77
  private
78
+ def handle_background(response)
79
+ return response unless
80
+ (job = response&.first).is_a?(::FrederickAPI::V2::BackgroundJob) && job.status != 'complete'
81
+ raise FrederickAPI::V2::Errors::BackgroundJobFailure, job if job.has_errors?
82
+ sleep job.retry_after
83
+ linked(job.links.attributes['self'])
84
+ end
33
85
 
34
86
  def handle_errors(result)
35
87
  return result unless result.has_errors?
@@ -37,6 +89,25 @@ module FrederickAPI
37
89
  FrederickAPI::V2::Errors::Error
38
90
  raise error_klass, result
39
91
  end
92
+
93
+ def make_request(type, path, params:, body:, headers:)
94
+ faraday_response = connection.run(type, path, params: params, body: body, headers: headers)
95
+ return klass.parser.parse(klass, faraday_response) unless faraday_response.status == 303
96
+
97
+ linked(faraday_response.headers['location'])
98
+ rescue JsonApiClient::Errors::ClientError => e
99
+ handle_json_api_client_error(e)
100
+ end
101
+
102
+ def get_via_post_path?(path)
103
+ GET_VIA_POST_PATHS.any? { |r| r.match(path) }
104
+ end
105
+
106
+ def handle_json_api_client_error(error)
107
+ raise error if JSON_API_CLIENT_PASSTHROUGH_ERRORS.include?(error.class)
108
+
109
+ klass.parser.parse(klass, error.env.response)
110
+ end
40
111
  end
41
112
  end
42
113
  end
@@ -10,6 +10,7 @@ module FrederickAPI
10
10
  self.query_builder = FrederickAPI::V2::Helpers::QueryBuilder
11
11
  self.paginator = FrederickAPI::V2::Helpers::Paginator
12
12
  self.requestor_class = FrederickAPI::V2::Helpers::Requestor
13
+ self.parser = ::FrederickAPI::V2::Helpers::BackgroundableParser
13
14
 
14
15
  attr_accessor :custom_headers
15
16
 
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FrederickAPI
4
+ module V2
5
+ # /v2/users
6
+ class Role < Resource
7
+ has_many :users
8
+ end
9
+ end
10
+ end
@@ -4,7 +4,8 @@ module FrederickAPI
4
4
  module V2
5
5
  # /v2/users
6
6
  class User < Resource
7
- has_many :roles
7
+ has_many :roles, class_name: 'FrederickAPI::V2::Role'
8
+ has_many :permitted_locations, class_name: 'FrederickAPI::V2::Location'
8
9
  end
9
10
  end
10
11
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module FrederickAPI
4
4
  # Current gem version
5
- VERSION = '0.4.3'
5
+ VERSION = '0.7'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frederick_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: '0.7'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frederick Engineering
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-09 00:00:00.000000000 Z
11
+ date: 2020-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json_api_client
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.5.3
19
+ version: 1.17.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.5.3
26
+ version: 1.17.1
27
27
  description: Ruby client for the Frederick API
28
28
  email:
29
29
  - tech@hirefrederick.com
@@ -36,13 +36,17 @@ files:
36
36
  - lib/frederick_api.rb
37
37
  - lib/frederick_api/configuration.rb
38
38
  - lib/frederick_api/v2/automation.rb
39
+ - lib/frederick_api/v2/background_job.rb
39
40
  - lib/frederick_api/v2/business_category.rb
41
+ - lib/frederick_api/v2/campaign.rb
40
42
  - lib/frederick_api/v2/communication_content.rb
41
43
  - lib/frederick_api/v2/contact.rb
42
44
  - lib/frederick_api/v2/contact_list.rb
43
45
  - lib/frederick_api/v2/contact_property.rb
44
46
  - lib/frederick_api/v2/contact_type.rb
47
+ - lib/frederick_api/v2/email_document.rb
45
48
  - lib/frederick_api/v2/errors/errors.rb
49
+ - lib/frederick_api/v2/helpers/backgroundable_parser.rb
46
50
  - lib/frederick_api/v2/helpers/has_many.rb
47
51
  - lib/frederick_api/v2/helpers/paginator.rb
48
52
  - lib/frederick_api/v2/helpers/query_builder.rb
@@ -51,13 +55,14 @@ files:
51
55
  - lib/frederick_api/v2/location.rb
52
56
  - lib/frederick_api/v2/public_resource.rb
53
57
  - lib/frederick_api/v2/resource.rb
58
+ - lib/frederick_api/v2/role.rb
54
59
  - lib/frederick_api/v2/user.rb
55
60
  - lib/frederick_api/version.rb
56
61
  homepage: https://github.com/HireFrederick/frederick_api_gem
57
62
  licenses:
58
63
  - MIT
59
64
  metadata: {}
60
- post_install_message:
65
+ post_install_message:
61
66
  rdoc_options: []
62
67
  require_paths:
63
68
  - lib
@@ -72,9 +77,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
77
  - !ruby/object:Gem::Version
73
78
  version: '0'
74
79
  requirements: []
75
- rubyforge_project:
76
- rubygems_version: 2.6.14
77
- signing_key:
80
+ rubygems_version: 3.0.8
81
+ signing_key:
78
82
  specification_version: 4
79
83
  summary: Frederick API Client
80
84
  test_files: []