frederick_api 0.4.2 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3405bd97d370f433b11cf71636a9a45eda63db2a
4
- data.tar.gz: c67e2e1aad4e82a35b454f6f926e9440061c86e1
2
+ SHA256:
3
+ metadata.gz: 9848d60ef419d88f6758574988f60f90337c64645316a0c716c12aaf497f43a9
4
+ data.tar.gz: 2e6096aeca9837b93ee25a2468bc7d3e2cf2712f6c735fb7330cf13a489f3b1e
5
5
  SHA512:
6
- metadata.gz: 425f96c7393736efcc851f35a1627f16007c1daba10d52c138f16f8e065832bd13f1f24326c0e7448ff613978a6ff8412a30cc621a11e5d39161563977257f28
7
- data.tar.gz: 278b005db0e22ca5f2791e3fa54b58d2ea29956a92ab3735a621b1a9e298c8c8f2bbbecb635e96c083690c7d8a128cddb73654088d024b64237457ed2e0ba420
6
+ metadata.gz: 06f920d1c60e09288bb9c75ef3b9be31168b93fe24ab681c33b1e2b77fb9127172e86608da5c8f862a43965867e1e33f571a91dfb80bd768cc9b227979b084dc
7
+ data.tar.gz: 738cf8ec474b270d81e79a95499325f62f70557baf09bc16220abd4d467564ead6607bf180bb22352bd309d78fdab6ce84435863341ea8c99c89985d430939b7
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,7 @@ 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'
32
35
 
33
36
  # Namespace for all Frederick API client methods/classes
34
37
  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
@@ -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,13 @@ module FrederickAPI
7
7
  class Requestor < JsonApiClient::Query::Requestor
8
8
  attr_reader :path
9
9
 
10
+ # Paths that may have an unbounded query param length so we should always use a POST
11
+ # instead of a GET to get around AWS Cloudfront limitations
12
+ GET_VIA_POST_PATHS = [
13
+ %r{^.*locations\/[^\/]+\/contacts$},
14
+ %r{^.*locations\/[^\/]+\/interactions$}
15
+ ].map(&:freeze).freeze
16
+
10
17
  def initialize(klass, path = nil)
11
18
  @klass = klass
12
19
  @path = path
@@ -21,15 +28,49 @@ module FrederickAPI
21
28
  end
22
29
  end
23
30
 
31
+ def get(params = {})
32
+ path = resource_path(params)
33
+
34
+ params.delete(klass.primary_key)
35
+ if get_via_post_path?(path)
36
+ return request(:post, path, body: params.to_json, additional_headers: { 'X-Request-Method' => 'GET' })
37
+ end
38
+
39
+ request(:get, path, params: params)
40
+ end
41
+
42
+ def linked(path)
43
+ uri = URI.parse(path)
44
+ return super unless get_via_post_path?(uri.path)
45
+
46
+ path_without_params = "#{uri.scheme}://#{uri.host}#{uri.path}"
47
+ params = uri.query ? CGI.parse(uri.query).each_with_object({}) { |(k, v), h| h[k] = v[0] } : {}
48
+ request(:post, path_without_params, params: params, additional_headers: { 'X-Request-Method' => 'GET' })
49
+ end
50
+
24
51
  # 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)
52
+ def request(type, path, params: nil, body: nil, additional_headers: {})
53
+ headers = klass.custom_headers.merge(additional_headers)
54
+ make_request = proc do
55
+ handle_background(handle_errors(make_request(type, path, params: params, body: body, headers: headers)))
56
+ end
57
+
58
+ begin
59
+ make_request.call
60
+ rescue JsonApiClient::Errors::ConnectionError, JsonApiClient::Errors::ServerError => ex
61
+ raise ex if ex.is_a?(JsonApiClient::Errors::NotFound) || ex.is_a?(JsonApiClient::Errors::Conflict)
62
+ make_request.call
63
+ end
30
64
  end
31
65
 
32
66
  private
67
+ def handle_background(response)
68
+ return response unless
69
+ (job = response&.first).is_a?(::FrederickAPI::V2::BackgroundJob) && job.status != 'complete'
70
+ raise FrederickAPI::V2::Errors::BackgroundJobFailure, job if job.has_errors?
71
+ sleep job.retry_after
72
+ linked(job.links.attributes['self'])
73
+ end
33
74
 
34
75
  def handle_errors(result)
35
76
  return result unless result.has_errors?
@@ -37,6 +78,18 @@ module FrederickAPI
37
78
  FrederickAPI::V2::Errors::Error
38
79
  raise error_klass, result
39
80
  end
81
+
82
+ def make_request(type, path, params:, body:, headers:)
83
+ faraday_response = connection.run(type, path, params: params, body: body, headers: headers)
84
+ return klass.parser.parse(klass, faraday_response) unless faraday_response.status == 303
85
+ linked(faraday_response.headers['location'])
86
+ rescue JsonApiClient::Errors::ClientError => ex
87
+ klass.parser.parse(klass, ex.env.response)
88
+ end
89
+
90
+ def get_via_post_path?(path)
91
+ GET_VIA_POST_PATHS.any? { |r| r.match(path) }
92
+ end
40
93
  end
41
94
  end
42
95
  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,6 +4,8 @@ module FrederickAPI
4
4
  module V2
5
5
  # /v2/users
6
6
  class User < Resource
7
+ has_many :roles, class_name: 'FrederickAPI::V2::Role'
8
+ has_many :permitted_locations, class_name: 'FrederickAPI::V2::Location'
7
9
  end
8
10
  end
9
11
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module FrederickAPI
4
4
  # Current gem version
5
- VERSION = '0.4.2'
5
+ VERSION = '0.6'
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.2
4
+ version: '0.6'
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: 2017-12-26 00:00:00.000000000 Z
11
+ date: 2020-09-25 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,6 +36,7 @@ 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
40
41
  - lib/frederick_api/v2/communication_content.rb
41
42
  - lib/frederick_api/v2/contact.rb
@@ -43,6 +44,7 @@ files:
43
44
  - lib/frederick_api/v2/contact_property.rb
44
45
  - lib/frederick_api/v2/contact_type.rb
45
46
  - lib/frederick_api/v2/errors/errors.rb
47
+ - lib/frederick_api/v2/helpers/backgroundable_parser.rb
46
48
  - lib/frederick_api/v2/helpers/has_many.rb
47
49
  - lib/frederick_api/v2/helpers/paginator.rb
48
50
  - lib/frederick_api/v2/helpers/query_builder.rb
@@ -51,13 +53,14 @@ files:
51
53
  - lib/frederick_api/v2/location.rb
52
54
  - lib/frederick_api/v2/public_resource.rb
53
55
  - lib/frederick_api/v2/resource.rb
56
+ - lib/frederick_api/v2/role.rb
54
57
  - lib/frederick_api/v2/user.rb
55
58
  - lib/frederick_api/version.rb
56
59
  homepage: https://github.com/HireFrederick/frederick_api_gem
57
60
  licenses:
58
61
  - MIT
59
62
  metadata: {}
60
- post_install_message:
63
+ post_install_message:
61
64
  rdoc_options: []
62
65
  require_paths:
63
66
  - lib
@@ -72,9 +75,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
72
75
  - !ruby/object:Gem::Version
73
76
  version: '0'
74
77
  requirements: []
75
- rubyforge_project:
76
- rubygems_version: 2.6.11
77
- signing_key:
78
+ rubygems_version: 3.0.8
79
+ signing_key:
78
80
  specification_version: 4
79
81
  summary: Frederick API Client
80
82
  test_files: []