nypl_sierra_api_client 1.0.3 → 1.3.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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nypl_sierra_api_client.rb +81 -16
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 227304609f16f96cf643ec758501e7ba23952da2c77cc513d6b08781622da9a8
4
- data.tar.gz: a723fc2eb6e3fc3e33937c513eaddaa05d7a194b9f11fc8eb12f9d2cfd7da594
3
+ metadata.gz: 7216ca46bebde733ae89eca1d88081d1d5cf2db7543dcdf801e433a4400ee4c4
4
+ data.tar.gz: bc2076e537315b8324bd4f54748090d68aa1d23c761aa9b44d948e95347864e8
5
5
  SHA512:
6
- metadata.gz: 213eed76eb255b12e38b00d7460dfb91bc8fac2afa2c92e025fb62019bee8a35d3c664b4713988865ed6b57327b736f3301858a40ae3a8019fad24e50342eb0e
7
- data.tar.gz: 97b00de6b5114deb32da9e72b3490e03e26077c9e23db72f015adc584c5a56a6b912798156fd59021c3d9a43840755b96c4e2b92a113c0a6216cde9edbb53cd5
6
+ metadata.gz: ee64dd2daae74d47757acba0df00a61c0e8b00d6f52a35a3c2c1fc53f43a8542436dac51463cd723c66333f122c70b07abe6db1e2ef7d78899f084206f14d29b
7
+ data.tar.gz: 7c09588f8be4a03f56519523008b116443930ef0b39880d14860305aa64278cbfec5a0ba1b9216ab1dced91b757013ed820abea4f0c96496488ec216ae023c86
@@ -27,6 +27,25 @@ class SierraApiClient
27
27
  config_defaults[:env].each do |key, value|
28
28
  raise SierraApiClientError.new "Missing config: neither config.#{key} nor ENV.#{value} are set" unless @config[key]
29
29
  end
30
+
31
+ @retries = 0
32
+ end
33
+
34
+ def put (path, body, options = {})
35
+ options = parse_http_options options
36
+ # Default to POSTing JSON unless explicitly stated otherwise
37
+ options[:headers]['Content-Type'] = 'application/json' unless options[:headers]['Content-Type']
38
+
39
+ do_request 'put', path, options do |request|
40
+ request.body = body
41
+ request.body = request.body.to_json unless options[:headers]['Content-Type'] != 'application/json'
42
+ end
43
+ end
44
+
45
+ def delete (path, options = {})
46
+ options = parse_http_options options
47
+
48
+ do_request 'delete', path, options
30
49
  end
31
50
 
32
51
  def get (path, options = {})
@@ -50,22 +69,19 @@ class SierraApiClient
50
69
  private
51
70
 
52
71
  def do_request (method, path, options = {})
53
- # For now, these are the methods we support:
54
- raise SierraApiClientError, "Unsupported method: #{method}" unless ['get', 'post'].include? method.downcase
55
72
 
56
- authenticate! if options[:authenticated]
73
+ raise SierraApiClientError, "Unsupported method: #{method}" unless ['get', 'post', 'put', 'delete'].include? method.downcase
57
74
 
58
- uri = URI.parse("#{@config[:base_url]}#{path}")
75
+ authenticate! if options[:authenticated]
59
76
 
60
- http = Net::HTTP.new(uri.host, uri.port)
61
- http.use_ssl = uri.scheme === 'https'
77
+ @uri = URI.parse("#{@config[:base_url]}#{path}")
62
78
 
63
79
  # Build request headers:
64
80
  request_headers = {}
65
81
  request_headers['Content-Type'] = options[:headers]['Content-Type'] unless options.dig(:headers, 'Content-Type').nil?
66
82
 
67
83
  # Create HTTP::Get or HTTP::Post
68
- request = Net::HTTP.const_get(method.capitalize).new(uri, request_headers)
84
+ request = Net::HTTP.const_get(method.capitalize).new(@uri, request_headers)
69
85
 
70
86
  # Add bearer token header
71
87
  request['Authorization'] = "Bearer #{@access_token}" if options[:authenticated]
@@ -73,31 +89,76 @@ class SierraApiClient
73
89
  # Allow caller to modify the request before we send it off:
74
90
  yield request if block_given?
75
91
 
76
- logger.debug "SierraApiClient: #{method} to Sierra api", { uri: uri, body: request.body }
92
+ logger.debug "SierraApiClient: #{method} to Sierra api", { uri: @uri, body: request.body }
93
+
94
+ execute request, options
95
+ end
96
+
97
+ def execute (request, options)
98
+ http = Net::HTTP.new(@uri.host, @uri.port)
99
+ http.use_ssl = @uri.scheme === 'https'
77
100
 
78
101
  begin
79
- # Execute request:
80
102
  response = http.request(request)
103
+ logger.debug "SierraApiClient: Got Sierra api response", { code: response.code, body: response.body }
81
104
  rescue => e
82
- raise SierraApiClientError.new(e), "Failed to #{method} to #{path}: #{e.message}"
105
+ raise SierraApiClientError.new "Failed to #{request.method} to #{request.path}: #{e.message}"
83
106
  end
84
107
 
85
- logger.debug "SierraApiClient: Got Sierra api response", { code: response.code, body: response.body }
86
-
87
- parse_response response
108
+ handle_response response, request, options
88
109
  end
89
110
 
90
- def parse_response (response)
111
+ def handle_response (response, request, options)
91
112
  if response.code == "401"
92
113
  # Likely an expired access-token; Wipe it for next run
93
- # TODO: Implement token refresh
94
114
  @access_token = nil
95
- raise SierraApiClientTokenError.new("Got a 401: #{response.body}")
115
+ if @retries < 3
116
+ if options[:authenticated]
117
+ logger.debug "SierraApiClient: Refreshing oauth token for 401", { code: 401, body: response.body, retry: @retries }
118
+
119
+ return reauthenticate_and_reattempt request, options
120
+ end
121
+ else
122
+ retries_exceeded = true
123
+ end
124
+
125
+ reset_retries
126
+ message = "Got a 401: #{retries_exceeded ? "Maximum retries exceeded, " : ''}#{response.body}"
127
+ raise SierraApiClientTokenError.new(message)
96
128
  end
97
129
 
130
+ if response.body == '' && response.code.to_i < 300 && response.code.to_i >= 200
131
+ reattempt_request request, options
132
+ end
133
+
134
+ reset_retries if @retries > 0
98
135
  SierraApiResponse.new(response)
99
136
  end
100
137
 
138
+
139
+ def reattempt_request request, options
140
+ if @retries < 3
141
+ logger.warn "#{request.method} request retry ##{@retries} due to empty response from Sierra API"
142
+ sleep 2 ** (@retries - 1)
143
+ @retries += 1
144
+ execute request, options
145
+ else
146
+ reset_retries
147
+ raise SierraApiResponseError.new "Sierra API Client: Request failed after 3 empty responses received from Sierra API"
148
+ end
149
+ end
150
+
151
+
152
+ def reauthenticate_and_reattempt request, options
153
+ @retries += 1
154
+ sleep 2 ** (@retries - 1)
155
+ authenticate!
156
+ # Reset bearer token header
157
+ request['Authorization'] = "Bearer #{@access_token}"
158
+
159
+ execute request, options
160
+ end
161
+
101
162
  def parse_http_options (_options)
102
163
  options = {
103
164
  authenticated: true
@@ -143,4 +204,8 @@ class SierraApiClient
143
204
  def logger
144
205
  @logger ||= NyplLogFormatter.new(STDOUT, level: @config[:log_level])
145
206
  end
207
+
208
+ def reset_retries
209
+ @retries = 0
210
+ end
146
211
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nypl_sierra_api_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - nonword