frederick_api 0.4.4 → 0.9
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 +5 -5
- data/README.md +26 -0
- data/lib/frederick_api.rb +6 -0
- data/lib/frederick_api/v2/automation.rb +2 -0
- data/lib/frederick_api/v2/automation_step.rb +14 -0
- data/lib/frederick_api/v2/background_job.rb +36 -0
- data/lib/frederick_api/v2/campaign.rb +12 -0
- data/lib/frederick_api/v2/communication_template.rb +8 -0
- data/lib/frederick_api/v2/email_document.rb +12 -0
- data/lib/frederick_api/v2/errors/errors.rb +4 -0
- data/lib/frederick_api/v2/helpers/backgroundable_parser.rb +18 -0
- data/lib/frederick_api/v2/helpers/has_many.rb +1 -1
- data/lib/frederick_api/v2/helpers/query_builder.rb +24 -14
- data/lib/frederick_api/v2/helpers/requestor.rb +76 -5
- data/lib/frederick_api/v2/resource.rb +11 -1
- data/lib/frederick_api/v2/user.rb +1 -0
- data/lib/frederick_api/version.rb +1 -1
- metadata +14 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: af582661b851880a278f82844f06ec98910f639cf0292ec1249f1ed1127b0a27
|
4
|
+
data.tar.gz: 5740b928ced7a2d9f4964388dbd5e543cbb0827c571f562899ab3a651a030f43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd740314950b62480828dc4878a603582edd4bf00c6bddc7e7a6b694707b90da52fd2e31ccdf226b86afeff09aeccd0a12d94b900f322a1e153a3e5a48ce9515
|
7
|
+
data.tar.gz: e535fb7f7655cbf975424497a333292d1dae97c9c8cb3f0621fac118f6e694d360dd355250f1ab91427144038c6a009392c37a0c47a64b4a9536b34a223a6582
|
data/README.md
CHANGED
@@ -88,6 +88,21 @@ FrederickAPI::V2::Location.with_access_token(access_token) do
|
|
88
88
|
end
|
89
89
|
```
|
90
90
|
|
91
|
+
### Using Headers
|
92
|
+
|
93
|
+
`Resource.with_access_token` is extended to take headers in the method `Resource.with_access_token_and_headers`. This is useful when we need to pass the universal customer to services that accept it.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
access_token = '9jsdo320fjfkfdksls30dfdcd919bcaa1b7804dbbebda0'
|
97
|
+
headers = { 'X-Universal-Customer': '{"source_platform":"mindbody","source_location_id":"1","source_customer_id":"77"}' }
|
98
|
+
|
99
|
+
FrederickAPI::V2::CommunicationTemplate.with_access_token_and_headers(access_token, headers) do
|
100
|
+
template = FrederickAPI::V2::CommunicationTemplate.create(template_attributes)
|
101
|
+
|
102
|
+
template.name
|
103
|
+
# => 'Name from Attrs'
|
104
|
+
end
|
105
|
+
```
|
91
106
|
### Nested Resources
|
92
107
|
|
93
108
|
Nested resources must be accessed using `where` to scope the request:
|
@@ -101,3 +116,14 @@ FrederickAPI::V2::Location.with_access_token(access_token) do
|
|
101
116
|
# => [...]
|
102
117
|
end
|
103
118
|
```
|
119
|
+
### Background Jobs
|
120
|
+
|
121
|
+
FrederickAPI Gem handles asynchronous responses as suggested in
|
122
|
+
[JSONApi Recommendations](https://jsonapi.org/recommendations/#asynchronous-processing)
|
123
|
+
[Asynchronous Processing](https://jsonapi.org/recommendations/#asynchronous-processing).
|
124
|
+
Polling until the job is complete, fetching and returning the completed resource.
|
125
|
+
|
126
|
+
* A FrederickAPI::V2::Errors::BackgroundJobFailure exception is raised if the API returns
|
127
|
+
an error on an asyncronous job.
|
128
|
+
* A BackgroundJob Resource will be returned from the client in the case that a successful
|
129
|
+
job does not return a resource.
|
data/lib/frederick_api.rb
CHANGED
@@ -12,17 +12,20 @@ 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'
|
23
25
|
|
24
26
|
# Core resources
|
25
27
|
require 'frederick_api/v2/automation'
|
28
|
+
require 'frederick_api/v2/automation_step'
|
26
29
|
require 'frederick_api/v2/communication_content'
|
27
30
|
require 'frederick_api/v2/contact'
|
28
31
|
require 'frederick_api/v2/contact_property'
|
@@ -30,6 +33,9 @@ require 'frederick_api/v2/contact_list'
|
|
30
33
|
require 'frederick_api/v2/contact_type'
|
31
34
|
require 'frederick_api/v2/interaction'
|
32
35
|
require 'frederick_api/v2/role'
|
36
|
+
require 'frederick_api/v2/campaign'
|
37
|
+
require 'frederick_api/v2/email_document'
|
38
|
+
require 'frederick_api/v2/communication_template'
|
33
39
|
|
34
40
|
# Namespace for all Frederick API client methods/classes
|
35
41
|
module FrederickAPI
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FrederickAPI
|
4
|
+
module V2
|
5
|
+
# Resource for automation step
|
6
|
+
class AutomationStep < Resource
|
7
|
+
belongs_to :location
|
8
|
+
has_one :automation
|
9
|
+
has_one :previous_automation_step, class_name: 'FrederickAPI::V2::AutomationStep'
|
10
|
+
|
11
|
+
self.read_only_attributes += %i[location_id]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -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,
|
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, body: params.to_json, additional_headers: { 'X-Request-Method' => 'GET' })
|
60
|
+
end
|
61
|
+
|
24
62
|
# Retry once on unhandled server errors
|
25
|
-
def request(type, path, params)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
|
@@ -35,7 +36,16 @@ module FrederickAPI
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def self.with_access_token(token)
|
38
|
-
|
39
|
+
with_access_token_and_headers(token) do
|
40
|
+
yield
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.with_access_token_and_headers(token, headers = {})
|
45
|
+
with_headers(
|
46
|
+
authorization: "Bearer #{token}",
|
47
|
+
**headers
|
48
|
+
) do
|
39
49
|
yield
|
40
50
|
end
|
41
51
|
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
|
+
version: '0.9'
|
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:
|
11
|
+
date: 2021-06-11 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.
|
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.
|
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,19 @@ 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/automation_step.rb
|
40
|
+
- lib/frederick_api/v2/background_job.rb
|
39
41
|
- lib/frederick_api/v2/business_category.rb
|
42
|
+
- lib/frederick_api/v2/campaign.rb
|
40
43
|
- lib/frederick_api/v2/communication_content.rb
|
44
|
+
- lib/frederick_api/v2/communication_template.rb
|
41
45
|
- lib/frederick_api/v2/contact.rb
|
42
46
|
- lib/frederick_api/v2/contact_list.rb
|
43
47
|
- lib/frederick_api/v2/contact_property.rb
|
44
48
|
- lib/frederick_api/v2/contact_type.rb
|
49
|
+
- lib/frederick_api/v2/email_document.rb
|
45
50
|
- lib/frederick_api/v2/errors/errors.rb
|
51
|
+
- lib/frederick_api/v2/helpers/backgroundable_parser.rb
|
46
52
|
- lib/frederick_api/v2/helpers/has_many.rb
|
47
53
|
- lib/frederick_api/v2/helpers/paginator.rb
|
48
54
|
- lib/frederick_api/v2/helpers/query_builder.rb
|
@@ -58,7 +64,7 @@ homepage: https://github.com/HireFrederick/frederick_api_gem
|
|
58
64
|
licenses:
|
59
65
|
- MIT
|
60
66
|
metadata: {}
|
61
|
-
post_install_message:
|
67
|
+
post_install_message:
|
62
68
|
rdoc_options: []
|
63
69
|
require_paths:
|
64
70
|
- lib
|
@@ -73,9 +79,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
79
|
- !ruby/object:Gem::Version
|
74
80
|
version: '0'
|
75
81
|
requirements: []
|
76
|
-
|
77
|
-
|
78
|
-
signing_key:
|
82
|
+
rubygems_version: 3.0.8
|
83
|
+
signing_key:
|
79
84
|
specification_version: 4
|
80
85
|
summary: Frederick API Client
|
81
86
|
test_files: []
|