whiplash-app 0.4.0 → 0.6.2
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/.gitignore +1 -0
- data/lib/errors/whiplash_api_error.rb +99 -0
- data/lib/whiplash/app.rb +9 -1
- data/lib/whiplash/app/api_config.rb +4 -0
- data/lib/whiplash/app/caching.rb +2 -2
- data/lib/whiplash/app/connections.rb +133 -5
- data/lib/whiplash/app/version.rb +1 -1
- data/whiplash-app.gemspec +2 -1
- metadata +23 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3d70f904d63e4b816748c23f7a3287763420f8c222b2e7e4c63519c63614613f
|
4
|
+
data.tar.gz: 3a267c71d211814b6e85bfd8fa8075d1f048a90f936187b4353a0d36bc40b4d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27d80f78a200d4d202b1236941ec7b7c5b3b2e185bdcf3c51ba98ce7304010cc258c350f2cf524d684343eae2c8111f837ced586b10fda93439ed2f1e608a556
|
7
|
+
data.tar.gz: 92bcf7a2e0bc197d7b97aba7d4748fe4759b9ede63cf60ec9027645b44ee4155057b2e6b63ed2177b2a6d208fb8563409cf2d7dae0bb68a04cca0e8c0eed8e8c
|
data/.gitignore
CHANGED
@@ -0,0 +1,99 @@
|
|
1
|
+
class WhiplashApiError < StandardError
|
2
|
+
class Deadlock < WhiplashApiError
|
3
|
+
end
|
4
|
+
|
5
|
+
class Timeout < WhiplashApiError
|
6
|
+
end
|
7
|
+
|
8
|
+
class Configuration < WhiplashApiError
|
9
|
+
end
|
10
|
+
|
11
|
+
class Inventory < WhiplashApiError
|
12
|
+
end
|
13
|
+
|
14
|
+
class Ignore < WhiplashApiError
|
15
|
+
end
|
16
|
+
|
17
|
+
# 400
|
18
|
+
class BadRequest < WhiplashApiError
|
19
|
+
end
|
20
|
+
|
21
|
+
# 401
|
22
|
+
class Unauthorized < WhiplashApiError
|
23
|
+
end
|
24
|
+
|
25
|
+
# 403
|
26
|
+
class Forbidden < WhiplashApiError
|
27
|
+
end
|
28
|
+
|
29
|
+
# 404
|
30
|
+
class RecordNotFound < WhiplashApiError
|
31
|
+
end
|
32
|
+
|
33
|
+
# 405
|
34
|
+
class MethodNotAllowed < WhiplashApiError
|
35
|
+
end
|
36
|
+
|
37
|
+
# 406
|
38
|
+
class NotAcceptable < WhiplashApiError
|
39
|
+
end
|
40
|
+
|
41
|
+
# 408
|
42
|
+
class Timeout < WhiplashApiError
|
43
|
+
end
|
44
|
+
|
45
|
+
# 409
|
46
|
+
class Conflict < WhiplashApiError
|
47
|
+
end
|
48
|
+
|
49
|
+
# 415
|
50
|
+
class UnsupportedMediaType < WhiplashApiError
|
51
|
+
end
|
52
|
+
|
53
|
+
# 422
|
54
|
+
class UnprocessableEntity < WhiplashApiError
|
55
|
+
end
|
56
|
+
|
57
|
+
# 429
|
58
|
+
class OverRateLimit < WhiplashApiError
|
59
|
+
end
|
60
|
+
|
61
|
+
class SSLError < WhiplashApiError
|
62
|
+
end
|
63
|
+
|
64
|
+
# 500+
|
65
|
+
class InternalServerError < WhiplashApiError
|
66
|
+
end
|
67
|
+
|
68
|
+
# 502
|
69
|
+
class Timeout < WhiplashApiError
|
70
|
+
end
|
71
|
+
|
72
|
+
# 503
|
73
|
+
class ServiceUnavailable < WhiplashApiError
|
74
|
+
end
|
75
|
+
|
76
|
+
# ???
|
77
|
+
class UnknownError < WhiplashApiError
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.codes
|
81
|
+
{
|
82
|
+
400 => WhiplashApiError::BadRequest,
|
83
|
+
401 => WhiplashApiError::Unauthorized,
|
84
|
+
403 => WhiplashApiError::Forbidden,
|
85
|
+
404 => WhiplashApiError::RecordNotFound,
|
86
|
+
405 => WhiplashApiError::MethodNotAllowed,
|
87
|
+
406 => WhiplashApiError::NotAcceptable,
|
88
|
+
408 => WhiplashApiError::Timeout,
|
89
|
+
409 => WhiplashApiError::Conflict,
|
90
|
+
415 => WhiplashApiError::UnsupportedMediaType,
|
91
|
+
422 => WhiplashApiError::UnprocessableEntity,
|
92
|
+
429 => WhiplashApiError::OverRateLimit,
|
93
|
+
495 => WhiplashApiError::SSLError,
|
94
|
+
500 => WhiplashApiError::InternalServerError,
|
95
|
+
502 => WhiplashApiError::Timeout,
|
96
|
+
503 => WhiplashApiError::ServiceUnavailable
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
data/lib/whiplash/app.rb
CHANGED
@@ -4,6 +4,7 @@ require "whiplash/app/connections"
|
|
4
4
|
require "whiplash/app/finder_methods"
|
5
5
|
require "whiplash/app/signing"
|
6
6
|
require "whiplash/app/version"
|
7
|
+
require "errors/whiplash_api_error"
|
7
8
|
require "oauth2"
|
8
9
|
require "faraday_middleware"
|
9
10
|
|
@@ -19,11 +20,18 @@ module Whiplash
|
|
19
20
|
|
20
21
|
def initialize(token=nil, options={})
|
21
22
|
opts = options.with_indifferent_access
|
23
|
+
token ||= cache_store["whiplash_api_token"]
|
22
24
|
@token = format_token(token) unless token.nil?
|
23
25
|
@customer_id = options[:customer_id]
|
24
26
|
@shop_id = options[:shop_id]
|
25
27
|
end
|
26
28
|
|
29
|
+
def self.whiplash_api_token
|
30
|
+
store = Moneta.new(:Redis, host: ENV["REDIS_HOST"], port: ENV["REDIS_PORT"], password: ENV["REDIS_PASSWORD"], expires: 7200)
|
31
|
+
cache_store = Moneta::Namespace.new store, Whiplash::App::Caching.namespace_value
|
32
|
+
cache_store["whiplash_api_token"]
|
33
|
+
end
|
34
|
+
|
27
35
|
def client
|
28
36
|
OAuth2::Client.new(ENV["WHIPLASH_CLIENT_ID"], ENV["WHIPLASH_CLIENT_SECRET"], site: api_url)
|
29
37
|
end
|
@@ -56,7 +64,7 @@ module Whiplash
|
|
56
64
|
|
57
65
|
def token_expired?
|
58
66
|
return token.expired? unless token.blank?
|
59
|
-
return true unless cache_store.
|
67
|
+
return true unless cache_store.key?("whiplash_api_token")
|
60
68
|
return true if cache_store["whiplash_api_token"].blank?
|
61
69
|
false
|
62
70
|
end
|
data/lib/whiplash/app/caching.rb
CHANGED
@@ -7,13 +7,13 @@ module Whiplash
|
|
7
7
|
def cache_store
|
8
8
|
if ENV["REDIS_HOST"]
|
9
9
|
store = Moneta.new(:Redis, host: ENV["REDIS_HOST"], port: ENV["REDIS_PORT"], password: ENV["REDIS_PASSWORD"], expires: 7200)
|
10
|
-
Moneta::Namespace.new store, namespace_value
|
10
|
+
Moneta::Namespace.new store, Whiplash::App::Caching.namespace_value
|
11
11
|
else
|
12
12
|
Moneta.new(:File, dir: "tmp", expires: 7200)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
def namespace_value
|
16
|
+
def self.namespace_value
|
17
17
|
ENV["REDIS_NAMESPACE"] || ENV["WHIPLASH_CLIENT_ID"]
|
18
18
|
end
|
19
19
|
|
@@ -2,7 +2,7 @@ module Whiplash
|
|
2
2
|
class App
|
3
3
|
module Connections
|
4
4
|
|
5
|
-
def
|
5
|
+
def base_app_request(options={})
|
6
6
|
if options[:params][:id]
|
7
7
|
endpoint = [options[:endpoint], options[:params].delete(:id)].join('/')
|
8
8
|
else
|
@@ -11,10 +11,49 @@ module Whiplash
|
|
11
11
|
options[:headers] ||= {}
|
12
12
|
options[:headers][:customer_id] ||= customer_id if customer_id
|
13
13
|
options[:headers][:shop_id] ||= shop_id if shop_id
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
|
15
|
+
args = [
|
16
|
+
options[:method],
|
17
|
+
endpoint,
|
18
|
+
options[:params],
|
19
|
+
sanitize_headers(options[:headers])
|
20
|
+
]
|
21
|
+
|
22
|
+
connection.send(*args)
|
23
|
+
end
|
24
|
+
|
25
|
+
def app_request(options={})
|
26
|
+
return base_app_request(options) unless defined?(Sidekiq)
|
27
|
+
limiter = Sidekiq::Limiter.window('whiplash-core', self.rate_limit, :second, wait_timeout: 15)
|
28
|
+
limiter.within_limit do
|
29
|
+
base_app_request(options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def app_request!(options = {})
|
34
|
+
begin
|
35
|
+
response = app_request(options)
|
36
|
+
return response if response.success?
|
37
|
+
message = response.body if response.body.is_a? String
|
38
|
+
message = response.body.dig('error') if response.body.respond_to?(:dig)
|
39
|
+
store_whiplash_error!(response.status)
|
40
|
+
error_response(response.status, message)
|
41
|
+
rescue Faraday::ConnectionFailed => e
|
42
|
+
case e.message
|
43
|
+
when 'end of file reached'
|
44
|
+
store_whiplash_error!(:eof, options)
|
45
|
+
Rails.logger.error "[Whiplash][EOF] Failed to connect to #{url}"
|
46
|
+
raise ProviderError::InternalServerError, e.message
|
47
|
+
when 'Net::OpenTimeout'
|
48
|
+
store_whiplash_error!(:timeout, options)
|
49
|
+
Rails.logger.error "[Whiplash][Timeout] Request to #{url} timed out"
|
50
|
+
raise ProviderError::Timeout, e.message
|
51
|
+
else
|
52
|
+
store_whiplash_error!(:connection, options)
|
53
|
+
Rails.logger.error "[Whiplash] Request to #{url} failed"
|
54
|
+
raise ProviderError::InternalServerError, e.message
|
55
|
+
end
|
56
|
+
end
|
18
57
|
end
|
19
58
|
|
20
59
|
def delete(endpoint, params = {}, headers = nil)
|
@@ -45,6 +84,65 @@ module Whiplash
|
|
45
84
|
headers: headers)
|
46
85
|
end
|
47
86
|
|
87
|
+
def delete!(endpoint, params = {}, headers = nil)
|
88
|
+
app_request!(method: :delete,
|
89
|
+
endpoint: endpoint,
|
90
|
+
params: params,
|
91
|
+
headers: headers)
|
92
|
+
end
|
93
|
+
|
94
|
+
def get!(endpoint, params = {}, headers = nil)
|
95
|
+
app_request!(method: :get,
|
96
|
+
endpoint: endpoint,
|
97
|
+
params: params,
|
98
|
+
headers: headers)
|
99
|
+
end
|
100
|
+
|
101
|
+
def post!(endpoint, params = {}, headers = nil)
|
102
|
+
app_request!(method: :post,
|
103
|
+
endpoint: endpoint,
|
104
|
+
params: params,
|
105
|
+
headers: headers)
|
106
|
+
end
|
107
|
+
|
108
|
+
def put!(endpoint, params = {}, headers = nil)
|
109
|
+
app_request!(method: :put,
|
110
|
+
endpoint: endpoint,
|
111
|
+
params: params,
|
112
|
+
headers: headers)
|
113
|
+
end
|
114
|
+
|
115
|
+
def get_body_or_empty(endpoint, params = {}, headers = nil)
|
116
|
+
response = get(endpoint, params, headers)
|
117
|
+
if !response.success?
|
118
|
+
case response.status
|
119
|
+
when 500
|
120
|
+
Appsignal.send_error(WhiplashApiError::InternalServerError.new(response.body), {raised: false})
|
121
|
+
else
|
122
|
+
end
|
123
|
+
|
124
|
+
case get_context(endpoint)
|
125
|
+
when 'collection'
|
126
|
+
Rails.logger.info "[WhiplashApi] Returned #{response.status}. Returning an empty array..."
|
127
|
+
return []
|
128
|
+
when 'member'
|
129
|
+
Rails.logger.info "[WhiplashApi] Returned #{response.status}. Returning nil..."
|
130
|
+
return nil
|
131
|
+
when 'aggregate'
|
132
|
+
Rails.logger.info "[WhiplashApi] Returned #{response.status}. Returning an empty hash..."
|
133
|
+
return {}
|
134
|
+
end
|
135
|
+
end
|
136
|
+
response.body
|
137
|
+
end
|
138
|
+
|
139
|
+
def get_context(endpoint)
|
140
|
+
parts = endpoint.split('/').compact
|
141
|
+
return 'member' if (parts.last =~ /\d+/).present?
|
142
|
+
return 'aggregate' if parts.include?('aggregate')
|
143
|
+
'collection'
|
144
|
+
end
|
145
|
+
|
48
146
|
def sanitize_headers(headers)
|
49
147
|
if headers
|
50
148
|
{}.tap do |hash|
|
@@ -55,6 +153,36 @@ module Whiplash
|
|
55
153
|
end
|
56
154
|
end
|
57
155
|
|
156
|
+
def store_whiplash_error!(error, options={})
|
157
|
+
return unless defined?(Appsignal)
|
158
|
+
options = options.with_indifferent_access
|
159
|
+
Appsignal.increment_counter(
|
160
|
+
"whiplash_error",
|
161
|
+
1.0,
|
162
|
+
shop_id: options[:shop_id],
|
163
|
+
customer_id: options[:customer_id],
|
164
|
+
error: error.to_s
|
165
|
+
)
|
166
|
+
end
|
167
|
+
|
168
|
+
def error_codes
|
169
|
+
WhiplashApiError.codes
|
170
|
+
end
|
171
|
+
|
172
|
+
def select_error(status_code)
|
173
|
+
unless error_codes.keys.include? status_code
|
174
|
+
Rails.logger.info "[Provider] Unknown status code from #{self.class.name}: #{status_code}"
|
175
|
+
return WhiplashApiError::UnknownError
|
176
|
+
end
|
177
|
+
error_codes[status_code]
|
178
|
+
end
|
179
|
+
|
180
|
+
# Select an applicable error message on a request to a provider.
|
181
|
+
def error_response(status_code, message=nil)
|
182
|
+
message ||= "Your request has been denied as a #{status_code} error"
|
183
|
+
raise select_error(status_code), message
|
184
|
+
end
|
185
|
+
|
58
186
|
end
|
59
187
|
end
|
60
188
|
end
|
data/lib/whiplash/app/version.rb
CHANGED
data/whiplash-app.gemspec
CHANGED
@@ -23,6 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_dependency "moneta", "~> 0.8.0"
|
24
24
|
|
25
25
|
spec.add_development_dependency "bundler", "~> 1.11"
|
26
|
-
spec.add_development_dependency "rake", "
|
26
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
27
27
|
spec.add_development_dependency "rspec", "~> 3.0"
|
28
|
+
spec.add_development_dependency "pry" , '~> 0.12.2'
|
28
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: whiplash-app
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Don Sullivan, Mark Dickson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: oauth2
|
@@ -70,16 +70,16 @@ dependencies:
|
|
70
70
|
name: rake
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - "
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: 12.3.3
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - "
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 12.3.3
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rspec
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '3.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.12.2
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.12.2
|
97
111
|
description: this gem provides connectivity to the Whiplash API for authentication
|
98
112
|
and REST requests.
|
99
113
|
email:
|
@@ -103,6 +117,7 @@ extensions: []
|
|
103
117
|
extra_rdoc_files: []
|
104
118
|
files:
|
105
119
|
- ".gitignore"
|
120
|
+
- ".idea/.gitignore"
|
106
121
|
- ".rspec"
|
107
122
|
- ".travis.yml"
|
108
123
|
- Gemfile
|
@@ -110,6 +125,7 @@ files:
|
|
110
125
|
- Rakefile
|
111
126
|
- bin/console
|
112
127
|
- bin/setup
|
128
|
+
- lib/errors/whiplash_api_error.rb
|
113
129
|
- lib/whiplash/app.rb
|
114
130
|
- lib/whiplash/app/api_config.rb
|
115
131
|
- lib/whiplash/app/caching.rb
|
@@ -138,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
154
|
version: '0'
|
139
155
|
requirements: []
|
140
156
|
rubyforge_project:
|
141
|
-
rubygems_version: 2.6.
|
157
|
+
rubygems_version: 2.7.6.2
|
142
158
|
signing_key:
|
143
159
|
specification_version: 4
|
144
160
|
summary: this gem provides connectivity to the Whiplash API for authentication and
|