ncore 2.3.3 → 3.0.0

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
2
  SHA256:
3
- metadata.gz: 57e1ee1a969b6a8679b297f537fe6d2c6d95418d75db88cce96c8342e3ff29ac
4
- data.tar.gz: 45b8e54512221b1510ed57a9c594d2818cf4b1b86dce448145d1786422c8e788
3
+ metadata.gz: 63b5e71f6a7f803b1a270e81b5f443f41490274387873395dbcc9c05a5cdcca2
4
+ data.tar.gz: 875e34f54fd4ba0e014c91ab371be8b6d1202e908cd6470b11666e12e82577b8
5
5
  SHA512:
6
- metadata.gz: a9b61a2fcba5cdd6640b37ba99400acd45348ae4ee65d51f56b4cb3a25a180670e3b4b02a53276b68fca0e77d5c669e0a835fe7c7057df9006e8e71e7b797080
7
- data.tar.gz: 7e146be87089170ce8fd889bcfc3c055caf476f918297707d174bc86ad395db7eaafc61e3c0e49c912b90909b675a61eec35b97d0be36897f8a7bec7d9bbd4c0
6
+ metadata.gz: 06c85c6685ae41485761e725fb370688846df1b38e5097cf60222f97c7040f2b94f74d250fb37efdc8feff8dbe3b15ca8e366ff2c9f87204de36bea395ee5d2a
7
+ data.tar.gz: f5ae351e39942821b41e95a6ae17baa9536696a806847c98e693f3526345c999ef42b9babee6b25fcbae5cf79efdaebd4341c14f01f4c91c6251b8a8320c7155
data/CHANGELOG.md CHANGED
@@ -1,25 +1,39 @@
1
- #### 2.3.3
2
-
3
- - Improve keepalive handling
4
-
5
- #### 2.3.2
6
-
7
- - Allow ActiveSupport 7.0
8
-
9
- #### 2.3.1
10
-
11
- - Allow ActiveSupport 6.1
12
-
13
- #### 2.3.0
14
-
15
- - Use system's CA certificate store by default (backport from v3.2.0)
16
- To use bundled CAs instead:
17
- SomeAppName::Api.ssl_cert_bundle = :bundled
18
- On failure reading specified bundle, raises exception instead of warning
19
-
20
- #### 2.2.2
21
-
22
- - Update certs
1
+ #### 3.0.0
2
+
3
+ BREAKING CHANGES
4
+ - Update has_many, belongs_to signatures
5
+ - Rename Base#url -> #resource_path
6
+ - Drop ActiveModel <= 4.1
7
+ - `#errors` is now always an ActiveModel::Errors instance
8
+
9
+ DEPRECATION NOTICE
10
+ - ValidationError is deprecated and will be removed in 3.1.
11
+
12
+ Other changes
13
+ - Add :cache option for requests
14
+ Set default store at MyApi::Api.cache_store=
15
+ See example railtie.rb for auto-config
16
+ Examples:
17
+ SomeResource.all(cache: true)
18
+ uses MyApi::Api.cache_store
19
+ SomeResource.find(id, cache: {expires_in: 5.minutes})
20
+ uses MyApi::Api.cache_store with specified options
21
+ SomeResource.find(id, cache: Dalli::Store.new(...))
22
+ uses provided cache store (with its default options)
23
+ - Make bearer_credential_key allow strings or symbols
24
+ - Warn on attr name collision
25
+ - Update CA certificates
26
+ - Better default output for #as_json
27
+ - Allow ActiveModel/Support 6.0
28
+ - Resolve deprecation messages on Ruby 2.6
29
+ - Add #factory
30
+ - API response :errors may be hash or array
31
+ - Add RecordInvalid#errors
32
+ - Better Ruby and ActiveModel integration
33
+ - #eql?, #==, #hash
34
+ - #model_name
35
+ - #i18n_scope, config via Api.i18n_scope=
36
+ - #cache_key, #cache_version, #cache_key_with_version
23
37
 
24
38
  #### 2.2.1
25
39
 
@@ -110,4 +124,4 @@
110
124
 
111
125
  #### 1.0.0
112
126
 
113
- - Initial release
127
+ - Initial release
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014-2018 Notioneer, Inc.
1
+ Copyright (c) 2014-2020 Notioneer, Inc.
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  NCore is a Ruby gem designed to help build REST API clients. It is not an API
4
4
  client by itself, but provides several useful building blocks to build one.
5
5
 
6
- It relies on `excon` for HTTP handling and `activesupport`.
6
+ It relies on `excon` for HTTP handling and `activemodel`.
7
7
 
8
8
  If present, uses `multi_json`. Otherwise, the stdlib 'json' is used.
9
9
  'multi_json' with an accelerated json gem is recommended.
@@ -21,6 +21,8 @@ module MyApi
21
21
 
22
22
  self.strict_attributes = false
23
23
 
24
+ self.i18n_scope = :my_api
25
+
24
26
  self.instrument_key = 'request.my_api'
25
27
 
26
28
  self.status_page = 'http://my.api.status.page'
@@ -30,6 +32,12 @@ module MyApi
30
32
  # self.bearer_credential_key = :api_key
31
33
 
32
34
  self.credentials_error_message = %Q{Missing API credentials. Set default credentials using "MyApi.credentials = {api_user: YOUR_API_USER, api_key: YOUR_API_KEY}"}
35
+
36
+ # self.verify_ssl = true
37
+
38
+ # self.ssl_cert_bundle = 'path/to/bundle.crt'
39
+
40
+ # self.logger = Logger.new(STDOUT)
33
41
  end
34
42
 
35
43
  end
@@ -1,6 +1,10 @@
1
1
  module MyApi
2
2
  class Railtie < Rails::Railtie
3
3
 
4
+ config.after_initialize do
5
+ MyApi::Api.cache_store = Rails.cache
6
+ end
7
+
4
8
  initializer "my_api.log_runtime" do |app|
5
9
  require 'my_api/rails/log_subscriber'
6
10
  ActiveSupport.on_load(:action_controller) do
@@ -1,17 +1,17 @@
1
1
  module NCore
2
2
  module Associations
3
3
 
4
- def has_many(assoc, klass=nil)
4
+ def has_many(assoc, class_name: nil)
5
5
  assoc = assoc.to_s
6
- klass ||= "#{module_name}::#{assoc.camelize.singularize}"
6
+ klass = class_name || "#{module_name}::#{assoc.camelize.singularize}"
7
7
  key = "#{attrib_name}_id"
8
8
  class_eval <<-M1, __FILE__, __LINE__+1
9
9
  def #{assoc}(params={})
10
10
  return [] unless id
11
11
  reload = params.delete :reload
12
- params = parse_request_params(params).reverse_merge credentials: api_creds
13
12
  cacheable = params.except(:credentials, :request).empty?
14
- params.merge! #{key}: id
13
+ params = parse_request_params(params).reverse_merge credentials: api_creds
14
+ params[:#{key}] = id
15
15
  if cacheable
16
16
  # only cache unfiltered, default api call
17
17
  @attribs[:#{assoc}] = (!reload && @attribs[:#{assoc}]) || #{klass}.all(params)
@@ -24,7 +24,7 @@ module NCore
24
24
  def find_#{assoc.singularize}(aid, params={})
25
25
  raise UnsavedObjectError unless id
26
26
  params = parse_request_params(params).reverse_merge credentials: api_creds
27
- params.merge! #{key}: id
27
+ params[:#{key}] = id
28
28
  #{klass}.find(aid, params)
29
29
  end
30
30
  M2
@@ -33,7 +33,7 @@ module NCore
33
33
  def create_#{assoc.singularize}(params={})
34
34
  raise UnsavedObjectError unless id
35
35
  params = parse_request_params(params).reverse_merge credentials: api_creds
36
- params.merge! #{key}: id
36
+ params[:#{key}] = id
37
37
  #{klass}.create(params)
38
38
  end
39
39
  M3
@@ -42,7 +42,7 @@ module NCore
42
42
  def update_#{assoc.singularize}(aid, params={})
43
43
  raise UnsavedObjectError unless id
44
44
  params = parse_request_params(params).reverse_merge credentials: api_creds
45
- params.merge! #{key}: id
45
+ params[:#{key}] = id
46
46
  #{klass}.update(aid, params)
47
47
  end
48
48
  M4
@@ -50,7 +50,7 @@ module NCore
50
50
  def create_#{assoc.singularize}!(params={})
51
51
  raise UnsavedObjectError unless id
52
52
  params = parse_request_params(params).reverse_merge credentials: api_creds
53
- params.merge! #{key}: id
53
+ params[:#{key}] = id
54
54
  #{klass}.create!(params)
55
55
  end
56
56
  M5
@@ -58,7 +58,7 @@ module NCore
58
58
  def update_#{assoc.singularize}!(aid, params={})
59
59
  raise UnsavedObjectError unless id
60
60
  params = parse_request_params(params).reverse_merge credentials: api_creds
61
- params.merge! #{key}: id
61
+ params[:#{key}] = id
62
62
  #{klass}.update!(aid, params)
63
63
  end
64
64
  M6
@@ -67,7 +67,7 @@ module NCore
67
67
  def delete_#{assoc.singularize}(aid, params={})
68
68
  raise UnsavedObjectError unless id
69
69
  params = parse_request_params(params).reverse_merge credentials: api_creds
70
- params.merge! #{key}: id
70
+ params[:#{key}] = id
71
71
  #{klass}.delete(aid, params)
72
72
  end
73
73
  M7
@@ -75,15 +75,15 @@ module NCore
75
75
  def delete_#{assoc.singularize}!(aid, params={})
76
76
  raise UnsavedObjectError unless id
77
77
  params = parse_request_params(params).reverse_merge credentials: api_creds
78
- params.merge! #{key}: id
78
+ params[:#{key}] = id
79
79
  #{klass}.delete!(aid, params)
80
80
  end
81
81
  M8
82
82
  end
83
83
 
84
- def belongs_to(assoc, klass=nil)
84
+ def belongs_to(assoc, class_name: nil)
85
85
  assoc = assoc.to_s
86
- klass ||= "#{module_name}::#{assoc.camelize}"
86
+ klass = class_name || "#{module_name}::#{assoc.camelize}"
87
87
  class_eval <<-M1, __FILE__, __LINE__+1
88
88
  attr :#{assoc}_id
89
89
  def #{assoc}(params={})
@@ -10,6 +10,7 @@ module NCore
10
10
  module ClassMethods
11
11
  def attr(*attrs)
12
12
  attrs.each do |attr|
13
+ check_existing_method(attr)
13
14
  class_eval <<-AR, __FILE__, __LINE__+1
14
15
  def #{attr}
15
16
  self[:#{attr}]
@@ -20,6 +21,7 @@ module NCore
20
21
 
21
22
  def attr_datetime(*attrs)
22
23
  attrs.each do |attr|
24
+ check_existing_method(attr)
23
25
  class_eval <<-AD, __FILE__, __LINE__+1
24
26
  def #{attr}
25
27
  case self[:#{attr}]
@@ -39,6 +41,7 @@ module NCore
39
41
 
40
42
  def attr_decimal(*attrs)
41
43
  attrs.each do |attr|
44
+ check_existing_method(attr)
42
45
  class_eval <<-AD, __FILE__, __LINE__+1
43
46
  def #{attr}
44
47
  case self[:#{attr}]
@@ -52,10 +55,19 @@ module NCore
52
55
  end
53
56
  end
54
57
 
58
+ def check_existing_method(attr)
59
+ if method_defined?(attr) || private_method_defined?(attr)
60
+ sc = self
61
+ sc = sc.superclass while sc.superclass != Object
62
+ warn "Warning: Existing method #{sc.name}##{attr} being overwritten at #{caller[3]}"
63
+ end
64
+ end
65
+
55
66
  def parse_request_params(params={}, opts={})
56
67
  params = params.with_indifferent_access
57
68
  req = params.delete(:request)
58
69
  creds = params.delete(:credentials)
70
+ cache = params.delete(:cache)
59
71
  if opts[:json_root]
60
72
  if params.key?(opts[:json_root])
61
73
  o = params
@@ -67,6 +79,7 @@ module NCore
67
79
  end
68
80
  o[:request] = req if req
69
81
  o[:credentials] = creds if creds
82
+ o[:cache] = cache if cache
70
83
  o
71
84
  end
72
85
  end
@@ -86,23 +99,18 @@ module NCore
86
99
  creds_attr = attribs.delete(:credentials)
87
100
  @api_creds = api_creds || creds_attr
88
101
 
89
- if attribs.keys.sort == %w(data error metadata)
90
- load_attrs = attribs
91
- else
92
- load_attrs = {
93
- metadata: attribs.delete(:metadata),
94
- errors: attribs.delete(:errors),
95
- data: attribs.delete(:data) || attribs
96
- }
97
- end
98
- load(load_attrs)
102
+ load(
103
+ metadata: attribs.delete(:metadata),
104
+ errors: attribs.delete(:errors),
105
+ data: attribs.delete(:data) || attribs
106
+ )
99
107
  end
100
108
 
101
109
 
102
110
  def attributes
103
111
  Util.deep_clone(@attribs)
104
112
  end
105
-
113
+ alias_method :as_json, :attributes
106
114
 
107
115
  def [](attr)
108
116
  @attribs[attr]
@@ -150,10 +158,10 @@ module NCore
150
158
  end
151
159
 
152
160
 
153
- def load(parsed)
154
- self.metadata = parsed[:metadata] || {}.with_indifferent_access
155
- self.errors = parsed[:errors] || {}.with_indifferent_access
156
- parsed[:data].each do |k,v|
161
+ def load(data:, errors: nil, metadata: nil)
162
+ self.metadata = metadata || {}.with_indifferent_access
163
+ self.errors = parse_errors(errors)
164
+ data.each do |k,v|
157
165
  if respond_to? "#{k}="
158
166
  send "#{k}=", self.class.interpret_type(v, api_creds)
159
167
  else
@@ -163,6 +171,17 @@ module NCore
163
171
  self
164
172
  end
165
173
 
174
+ def parse_errors(errors)
175
+ errors ||= []
176
+ if errors.is_a?(::ActiveModel::Errors)
177
+ errors
178
+ else
179
+ ::ActiveModel::Errors.new(self).tap do |e0|
180
+ errors.each{|msg| e0.add :base, msg }
181
+ end
182
+ end
183
+ end
184
+
166
185
  end
167
186
 
168
187
 
data/lib/ncore/base.rb CHANGED
@@ -4,8 +4,10 @@ module NCore
4
4
 
5
5
  included do
6
6
  extend Associations
7
+ include ActiveModel
7
8
  include Attributes
8
9
  include Client
10
+ include Client::Cache
9
11
  include Identity
10
12
  include Lifecycle
11
13
  include Util
@@ -23,13 +25,13 @@ module NCore
23
25
  include Update if types.include? :update
24
26
  end
25
27
 
26
- def url
28
+ def resource_path
27
29
  class_name.underscore.pluralize
28
30
  end
29
31
  end
30
32
 
31
- def url
32
- "#{self.class.url}/#{CGI.escape((id||'-').to_s)}"
33
+ def resource_path
34
+ "#{self.class.resource_path}/#{CGI.escape((id||'-').to_s)}"
33
35
  end
34
36
 
35
37
  end
data/lib/ncore/client.rb CHANGED
@@ -6,11 +6,12 @@ module NCore
6
6
 
7
7
  module ClassMethods
8
8
 
9
- # opts - {params: {}, headers: {}, credentials: {}}
9
+ # opts - {params: {}, headers: {}, credentials: {}, cache: {}}
10
10
  # unknown keys assumed to be :params if :params is missing
11
11
  def request(method, url, opts={})
12
12
  opts = opts.with_indifferent_access
13
13
  request_credentials = opts.delete 'credentials'
14
+ cache_opts = opts.delete 'cache'
14
15
  headers = opts.delete('headers') || {}
15
16
  params = opts['params'] || opts
16
17
 
@@ -48,7 +49,7 @@ module NCore
48
49
  write_timeout: 50,
49
50
  }
50
51
 
51
- response = execute_request(rest_opts)
52
+ response = execute_request(rest_opts, cache_opts)
52
53
  parsed = parse_response(response)
53
54
  [parsed, request_credentials]
54
55
  end
@@ -58,7 +59,7 @@ module NCore
58
59
 
59
60
  def retrieve_credentials
60
61
  if credentials.blank?
61
- raise parent::Error, credentials_error_message
62
+ raise module_parent::Error, credentials_error_message
62
63
  end
63
64
  credentials
64
65
  end
@@ -69,7 +70,7 @@ module NCore
69
70
 
70
71
  def retrieve_default_url
71
72
  if default_url.blank?
72
- raise parent::Error, credentials_error_message
73
+ raise module_parent::Error, credentials_error_message
73
74
  end
74
75
  default_url
75
76
  end
@@ -87,12 +88,12 @@ module NCore
87
88
 
88
89
  def build_query_string(params)
89
90
  if params.any?
90
- query_string = params.map do |k,v|
91
+ query_string = params.sort.map do |k,v|
91
92
  if v.is_a?(Array)
92
93
  if v.empty?
93
94
  "#{k.to_s}[]="
94
95
  else
95
- v.map do |v2|
96
+ v.sort.map do |v2|
96
97
  "#{k.to_s}[]=#{CGI::escape(v2.to_s)}"
97
98
  end.join('&')
98
99
  end
@@ -163,7 +164,7 @@ module NCore
163
164
  end
164
165
 
165
166
 
166
- def execute_request(rest_opts)
167
+ def execute_request(rest_opts, _)
167
168
  debug_request rest_opts if debug
168
169
 
169
170
  tries = 0
@@ -176,7 +177,7 @@ module NCore
176
177
  tries += 1
177
178
  response = connection.request rest_opts.except(:url)
178
179
  rescue Excon::Error::Socket, Excon::Errors::SocketError, Excon::Error::Timeout,
179
- Errno::EADDRNOTAVAIL, Errno::ECONNRESET => e
180
+ Errno::EADDRNOTAVAIL => e
180
181
  # retry when keepalive was closed
181
182
  if tries <= 1 #&& e.message =~ /end of file reached/
182
183
  retry
@@ -188,30 +189,30 @@ module NCore
188
189
  debug_response response if debug
189
190
  end
190
191
  rescue Errno::ECONNRESET
191
- raise parent::ConnectionError, "Connection reset for #{host_for_error rest_opts[:url]} : check network or visit #{status_page}."
192
+ raise module_parent::ConnectionError, "Connection reset for #{host_for_error rest_opts[:url]} : check network or visit #{status_page}."
192
193
  rescue Errno::ECONNREFUSED
193
- raise parent::ConnectionError, "Connection error for #{host_for_error rest_opts[:url]} : check network and DNS or visit #{status_page}."
194
+ raise module_parent::ConnectionError, "Connection error for #{host_for_error rest_opts[:url]} : check network and DNS or visit #{status_page}."
194
195
  rescue Excon::Error::Timeout => e
195
196
  case e.message
196
197
  when /timeout reached/
197
- raise parent::ConnectionError, "Connection error for #{host_for_error rest_opts[:url]} : check network and DNS or visit #{status_page}."
198
+ raise module_parent::ConnectionError, "Connection error for #{host_for_error rest_opts[:url]} : check network and DNS or visit #{status_page}."
198
199
  else
199
200
  raise e
200
201
  end
201
202
  rescue Excon::Errors::SocketError => e
202
203
  case e.message
203
204
  when /Unable to verify certificate/
204
- raise parent::ConnectionError, "Unable to verify certificate for #{host_for_error rest_opts[:url]} : verify URL, set ssl_cert_bundle=, or disable SSL certificate verification (insecure)."
205
+ raise module_parent::ConnectionError, "Unable to verify certificate for #{host_for_error rest_opts[:url]} : verify URL or disable SSL certificate verification (insecure)."
205
206
  when /Name or service not known/, /No address associated with hostname/
206
- raise parent::ConnectionError, "DNS error for #{host_for_error rest_opts[:url]} : check network and DNS or visit #{status_page}."
207
+ raise module_parent::ConnectionError, "DNS error for #{host_for_error rest_opts[:url]} : check network and DNS or visit #{status_page}."
207
208
  when /Errno::ECONNREFUSED/
208
- raise parent::ConnectionError, "Connection error for #{host_for_error rest_opts[:url]} : check network and DNS or visit #{status_page}."
209
+ raise module_parent::ConnectionError, "Connection error for #{host_for_error rest_opts[:url]} : check network and DNS or visit #{status_page}."
209
210
  else
210
211
  raise e
211
212
  end
212
213
  rescue SocketError => e
213
214
  if e.message =~ /nodename nor servname provided/
214
- raise parent::ConnectionError, "DNS error for #{host_for_error rest_opts[:url]} : check network and DNS or visit #{status_page}."
215
+ raise module_parent::ConnectionError, "DNS error for #{host_for_error rest_opts[:url]} : check network and DNS or visit #{status_page}."
215
216
  else
216
217
  raise e
217
218
  end
@@ -219,21 +220,21 @@ module NCore
219
220
 
220
221
  case response.status
221
222
  when 401 # API auth valid; API call itself is an auth-related call and failed
222
- raise parent::AuthenticationFailed
223
+ raise module_parent::AuthenticationFailed
223
224
  when 402
224
- raise parent::AccountInactive, "Account inactive; login to portal to check account status."
225
+ raise module_parent::AccountInactive, "Account inactive; login to portal to check account status."
225
226
  when 403 # API auth failed or insufficient permissions
226
- raise parent::AccessDenied, "Access denied; check your API credentials and permissions."
227
+ raise module_parent::AccessDenied, "Access denied; check your API credentials and permissions."
227
228
  when 404
228
- raise parent::RecordNotFound
229
+ raise module_parent::RecordNotFound
229
230
  when 409, 422
230
231
  # pass through
231
232
  when 429
232
- raise parent::RateLimited
233
+ raise module_parent::RateLimited
233
234
  when 400..499
234
- raise parent::Error, "Client error: #{response.status}\n #{response.body}"
235
+ raise module_parent::Error, "Client error: #{response.status}\n #{response.body}"
235
236
  when 500..599
236
- raise parent::Error, "Server error: #{response.status}\n #{response.body}"
237
+ raise module_parent::Error, "Server error: #{response.status}\n #{response.body}"
237
238
  end
238
239
  response
239
240
  end
@@ -246,20 +247,20 @@ module NCore
246
247
  begin
247
248
  json = MultiJson.load(response.body, symbolize_keys: false) || {}
248
249
  rescue MultiJson::ParseError
249
- raise parent::Error, "Unable to parse API response; HTTP status: #{response.status}; body: #{response.body.inspect}"
250
+ raise module_parent::Error, "Unable to parse API response; HTTP status: #{response.status}; body: #{response.body.inspect}"
250
251
  end
251
252
  else
252
253
  begin
253
254
  json = JSON.parse(response.body, symbolize_names: false) || {}
254
255
  rescue JSON::ParserError
255
- raise parent::Error, "Unable to parse API response; HTTP status: #{response.status}; body: #{response.body.inspect}"
256
+ raise module_parent::Error, "Unable to parse API response; HTTP status: #{response.status}; body: #{response.body.inspect}"
256
257
  end
257
258
  end
258
259
  end
259
260
  json = json.with_indifferent_access
260
261
  errors = json.delete(:errors) || []
261
262
  if errors.any?
262
- errors = errors.values.flatten
263
+ errors = errors.values.flatten if errors.is_a?(Hash)
263
264
  metadata, json = json, {}
264
265
  else
265
266
  errors = []
@@ -296,16 +297,17 @@ module NCore
296
297
 
297
298
  def verify_ssl_cert?
298
299
  return @verify_ssl_cert unless @verify_ssl_cert.nil?
299
- if verify_ssl
300
- if ssl_cert_bundle
301
- bundle_readable = File.readable?(ssl_cert_bundle) rescue false
302
- unless bundle_readable
303
- raise parent::CertificateError, "Unable to read SSL cert bundle #{ssl_cert_bundle}."
304
- end
305
- end
300
+ bundle_readable = File.readable?(ssl_cert_bundle)
301
+ if verify_ssl && bundle_readable
306
302
  @verify_ssl_cert = true
307
303
  else
308
- m = "WARNNG: SSL cert verification is disabled. Enable verification with: #{parent}::Api.verify_ssl = true."
304
+ m = 'WARNNG: SSL cert verification is disabled.'
305
+ unless verify_ssl
306
+ m += " Enable verification with: #{module_parent}::Api.verify_ssl = true."
307
+ end
308
+ unless bundle_readable
309
+ m += " Unable to read CA bundle #{ssl_cert_bundle}."
310
+ end
309
311
  $stderr.puts m
310
312
  @verify_ssl_cert = false
311
313
  end
@@ -0,0 +1,48 @@
1
+ module NCore
2
+ module Client::Cache
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+
7
+ private
8
+
9
+ # cache_opts: true
10
+ # use *::Api.cache_store
11
+ # cache_opts: {...}
12
+ # use: *::Api.cache_store, with options: {...}
13
+ # hint: add force: true execute the query and rewrite the cache
14
+ # cache_opts: Store.new
15
+ # use Store.new as-is
16
+ def execute_request(req, cache_opts=nil)
17
+ case cache_opts
18
+ when true
19
+ store, cache_opts = cache_store, {}
20
+ when Hash
21
+ store, cache_opts = cache_store, cache_opts.symbolize_keys
22
+ when nil, false
23
+ store = false
24
+ else
25
+ store, cache_opts = cache_opts, {}
26
+ end
27
+
28
+ if store && req[:method] == :get
29
+ store.fetch request_cache_key(req.slice(:url, :headers)), cache_opts do
30
+ super
31
+ end
32
+ else
33
+ super
34
+ end
35
+ end
36
+
37
+
38
+ def request_cache_key(url:, headers:)
39
+ [ 'ncore',
40
+ url.gsub(/[^a-zA-Z0-9]+/,'-'),
41
+ Digest::MD5.hexdigest(headers.sort.to_s)
42
+ ].join ':'
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
@@ -28,6 +28,9 @@ module NCore
28
28
  mattr_accessor :strict_attributes
29
29
  self.strict_attributes = true
30
30
 
31
+ mattr_accessor :i18n_scope
32
+ self.i18n_scope = :ncore
33
+
31
34
  mattr_accessor :instrument_key
32
35
  self.instrument_key = 'request.ncore'
33
36
 
@@ -37,42 +40,31 @@ module NCore
37
40
  mattr_accessor :auth_header_prefix
38
41
  self.auth_header_prefix = 'X-Api'
39
42
 
40
- mattr_accessor :bearer_credential_key
43
+ mattr_reader :bearer_credential_key
44
+ class_eval <<-MTH
45
+ def self.bearer_credential_key=(v)
46
+ @@bearer_credential_key = v&.to_s
47
+ end
48
+ def bearer_credential_key=(v)
49
+ @@bearer_credential_key = v&.to_s
50
+ end
51
+ MTH
41
52
 
42
53
  mattr_accessor :credentials_error_message
43
- self.credentials_error_message = %Q{Missing API credentials. Set default credentials using "#{self.parent.name}.credentials = {api_user: YOUR_API_USER, api_key: YOUR_API_KEY}"}
54
+ self.credentials_error_message = %Q{Missing API credentials. Set default credentials using "#{self.module_parent.name}.credentials = {api_user: YOUR_API_USER, api_key: YOUR_API_KEY}"}
44
55
 
45
56
  mattr_accessor :verify_ssl
46
57
  self.verify_ssl = true
47
58
 
48
- mattr_reader :ssl_cert_bundle
49
- class_eval <<-MTH
50
- def self.ssl_cert_bundle=(v)
51
- v = find_excon_bundle if v==:bundled
52
- @@ssl_cert_bundle = v
53
- end
54
- def ssl_cert_bundle=(v)
55
- v = find_excon_bundle if v==:bundled
56
- @@ssl_cert_bundle = v
57
- end
58
- MTH
59
+ mattr_accessor :ssl_cert_bundle
60
+ self.ssl_cert_bundle = File.dirname(__FILE__)+'/ssl/ca-certificates.crt'
61
+
62
+ mattr_accessor :cache_store
59
63
 
60
64
  mattr_accessor :logger
61
65
  self.logger = Logger.new(STDOUT)
62
66
  end
63
67
 
64
-
65
- private
66
-
67
- def find_excon_bundle
68
- b = Gem.find_files_from_load_path('../data/cacert.pem').select{|p| p=~/excon/}.first
69
- if b
70
- b.freeze
71
- else
72
- raise parent::CertificateError, 'Failed to locate CA cert bundle from excon. Specify a full path instead.'
73
- end
74
- end
75
-
76
68
  end
77
69
 
78
70
  end