dor-services-client 8.8.0 → 9.1.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 +4 -4
- data/.rubocop.yml +6 -0
- data/.rubocop_todo.yml +0 -12
- data/dor-services-client.gemspec +1 -1
- data/lib/dor/services/client/marcxml.rb +4 -4
- data/lib/dor/services/client/mutate.rb +13 -5
- data/lib/dor/services/client/object.rb +11 -3
- data/lib/dor/services/client/object_metadata.rb +3 -2
- data/lib/dor/services/client/objects.rb +3 -16
- data/lib/dor/services/client/version.rb +1 -1
- data/lib/dor/services/client/versioned_service.rb +31 -16
- data/lib/dor/services/client.rb +24 -1
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4b8ec2c059acbd588a6d64e931035f5552b16bacf9d0e6a1f0b8194fb371bb2
|
4
|
+
data.tar.gz: 750be3e2a2a234299c63ee1aeb6b40c4a0a87116785cf085bc359d80676465da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0ffa417486e6136c276b2aa289d4f17e01a798ea288e727ce5b2955b722934ce7b992318ff3c88e3060a57a7cfd2a203b29d0302c6862d79cce80e6f4bab1d9
|
7
|
+
data.tar.gz: f707910e959af48ab45e29a4328217517b42c50f49314ff14e142afed33688d842b2ecfc9df8ea740e59914c31cbbd4d5b5dbff67cbb7b6e1b64e197a7aa1618
|
data/.rubocop.yml
CHANGED
@@ -12,6 +12,12 @@ Metrics/BlockLength:
|
|
12
12
|
- 'dor-services-client.gemspec'
|
13
13
|
- 'spec/**/*'
|
14
14
|
|
15
|
+
RSpec/MultipleMemoizedHelpers:
|
16
|
+
Max: 10
|
17
|
+
|
18
|
+
RSpec/ExampleLength:
|
19
|
+
Max: 10
|
20
|
+
|
15
21
|
Gemspec/DateAssignment: # (new in 1.10)
|
16
22
|
Enabled: true
|
17
23
|
Layout/SpaceBeforeBrackets: # (new in 1.7)
|
data/.rubocop_todo.yml
CHANGED
@@ -25,12 +25,6 @@ RSpec/AnyInstance:
|
|
25
25
|
- 'spec/dor/services/client/metadata_spec.rb'
|
26
26
|
- 'spec/dor/services/client/object_version_spec.rb'
|
27
27
|
|
28
|
-
# Offense count: 1
|
29
|
-
# Configuration parameters: Max, CountAsOne.
|
30
|
-
RSpec/ExampleLength:
|
31
|
-
Exclude:
|
32
|
-
- 'spec/dor/services/client/metadata_spec.rb'
|
33
|
-
|
34
28
|
# Offense count: 6
|
35
29
|
RSpec/IdenticalEqualityAssertion:
|
36
30
|
Exclude:
|
@@ -46,12 +40,6 @@ RSpec/MultipleExpectations:
|
|
46
40
|
- 'spec/dor/services/client/object_spec.rb'
|
47
41
|
- 'spec/dor/services/client/response_error_formatter_spec.rb'
|
48
42
|
|
49
|
-
# Offense count: 7
|
50
|
-
# Configuration parameters: AllowSubject, Max.
|
51
|
-
RSpec/MultipleMemoizedHelpers:
|
52
|
-
Exclude:
|
53
|
-
- 'spec/dor/services/client/objects_spec.rb'
|
54
|
-
|
55
43
|
# Offense count: 1
|
56
44
|
# Cop supports --auto-correct.
|
57
45
|
RSpec/MultipleSubjects:
|
data/dor-services-client.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.required_ruby_version = '>= 2.7', '< 4' # dor-services-app needs 2.7 due to fedora3
|
26
26
|
|
27
27
|
spec.add_dependency 'activesupport', '>= 4.2', '< 8'
|
28
|
-
spec.add_dependency 'cocina-models', '~> 0.
|
28
|
+
spec.add_dependency 'cocina-models', '~> 0.75.0' # leave pinned to patch level until cocina-models hits 1.0
|
29
29
|
spec.add_dependency 'deprecation', '>= 0'
|
30
30
|
spec.add_dependency 'faraday', '~> 2.0'
|
31
31
|
spec.add_dependency 'faraday-retry'
|
@@ -20,9 +20,9 @@ module Dor
|
|
20
20
|
|
21
21
|
# This method needs its own exception handling logic due to how the endpoint service (SearchWorks) operates
|
22
22
|
# raise a NotFoundResponse because the resource being requested was not found in the ILS (via dor-services-app)
|
23
|
-
raise NotFoundResponse
|
23
|
+
raise NotFoundResponse.new(response: resp) if resp.success? && resp.body.blank?
|
24
24
|
|
25
|
-
raise UnexpectedResponse
|
25
|
+
raise UnexpectedResponse.new(response: resp)
|
26
26
|
end
|
27
27
|
|
28
28
|
# Gets MARCXML corresponding to a barcode or catkey
|
@@ -45,9 +45,9 @@ module Dor
|
|
45
45
|
# DOR Services App does not respond with a 404 when no match in Symphony.
|
46
46
|
# Rather, it responds with a 500 containing "Record not found in Symphony" in the body.
|
47
47
|
# raise a NotFoundResponse because the resource being requested was not found in the ILS (via dor-services-app)
|
48
|
-
raise NotFoundResponse
|
48
|
+
raise NotFoundResponse.new(response: resp) if !resp.success? && resp.body.match?(/Record not found in Symphony/)
|
49
49
|
|
50
|
-
raise UnexpectedResponse
|
50
|
+
raise UnexpectedResponse.new(response: resp) unless resp.success?
|
51
51
|
|
52
52
|
resp.body
|
53
53
|
end
|
@@ -26,23 +26,31 @@ module Dor
|
|
26
26
|
end
|
27
27
|
|
28
28
|
# Updates the object
|
29
|
-
# @param [Cocina::Models::DRO
|
29
|
+
# @param [Cocina::Models::DROWithMetadata|CollectionWithMetadata|AdminPolicyWithMetadata|DRO|Collection|AdminPolicy] params model object
|
30
|
+
# @param [boolean] skip_lock do not provide ETag
|
30
31
|
# @raise [NotFoundResponse] when the response is a 404 (object not found)
|
31
32
|
# @raise [UnexpectedResponse] when the response is not successful.
|
32
|
-
# @
|
33
|
-
|
33
|
+
# @raise [BadRequestError] when ETag not provided.
|
34
|
+
# @return [Cocina::Models::DROWithMetadata,Cocina::Models::CollectionWithMetadata,Cocina::Models::AdminPolicyWithMetadata] the returned model
|
35
|
+
# rubocop:disable Metrics/AbcSize
|
36
|
+
def update(params:, skip_lock: false)
|
37
|
+
# Raised if Cocina::Models::*WithMetadata not provided.
|
38
|
+
raise ArgumentError, 'ETag not provided.' unless skip_lock || params.respond_to?(:lock)
|
39
|
+
|
34
40
|
resp = connection.patch do |req|
|
35
41
|
req.url object_path
|
36
42
|
req.headers['Content-Type'] = 'application/json'
|
37
43
|
# asking the service to return JSON (else it'll be plain text)
|
38
44
|
req.headers['Accept'] = 'application/json'
|
39
|
-
req.
|
45
|
+
req.headers['If-Match'] = params[:lock] unless skip_lock
|
46
|
+
req.body = build_json_from_cocina(params)
|
40
47
|
end
|
41
48
|
|
42
49
|
raise_exception_based_on_response!(resp) unless resp.success?
|
43
50
|
|
44
|
-
|
51
|
+
build_cocina_from_response(resp)
|
45
52
|
end
|
53
|
+
# rubocop:enable Metrics/AbcSize
|
46
54
|
|
47
55
|
# Pull in metadata from Symphony and updates descriptive metadata
|
48
56
|
# @raise [NotFoundResponse] when the response is a 404 (object not found)
|
@@ -45,9 +45,14 @@ module Dor
|
|
45
45
|
# Retrieves the Cocina model
|
46
46
|
# @raise [NotFoundResponse] when the response is a 404 (object not found)
|
47
47
|
# @raise [UnexpectedResponse] when the response is not successful.
|
48
|
-
# @return [Cocina::Models::
|
48
|
+
# @return [Cocina::Models::DROWithMetadata,Cocina::Models::CollectionWithMetadata,Cocina::Models::AdminPolicyWithMetadata] the returned model
|
49
49
|
def find
|
50
|
-
|
50
|
+
resp = connection.get do |req|
|
51
|
+
req.url object_path
|
52
|
+
end
|
53
|
+
raise_exception_based_on_response!(resp) unless resp.success?
|
54
|
+
|
55
|
+
build_cocina_from_response(resp)
|
51
56
|
end
|
52
57
|
|
53
58
|
# Retrieves the Cocina model and response metadata
|
@@ -64,9 +69,12 @@ module Dor
|
|
64
69
|
model = Cocina::Models.build(JSON.parse(resp.body))
|
65
70
|
|
66
71
|
# Don't use #slice here as Faraday will downcase the keys.
|
67
|
-
metadata = ObjectMetadata.new(updated_at: resp.headers['Last-Modified'],
|
72
|
+
metadata = ObjectMetadata.new(updated_at: resp.headers['Last-Modified'],
|
73
|
+
created_at: resp.headers['X-Created-At'],
|
74
|
+
etag: resp.headers['ETag'])
|
68
75
|
[model, metadata]
|
69
76
|
end
|
77
|
+
deprecation_deprecate find_with_metadata: 'Use find instead with provides models with metadata.'
|
70
78
|
|
71
79
|
# Get a list of the collections. (Similar to Valkyrie's find_inverse_references_by)
|
72
80
|
# @raise [UnexpectedResponse] if the request is unsuccessful.
|
@@ -9,11 +9,12 @@ module Dor
|
|
9
9
|
class ObjectMetadata
|
10
10
|
extend Deprecation
|
11
11
|
|
12
|
-
attr_reader :created_at, :updated_at
|
12
|
+
attr_reader :created_at, :updated_at, :etag
|
13
13
|
|
14
|
-
def initialize(created_at:, updated_at:)
|
14
|
+
def initialize(created_at:, updated_at:, etag: nil)
|
15
15
|
@created_at = created_at
|
16
16
|
@updated_at = updated_at
|
17
|
+
@etag = etag
|
17
18
|
end
|
18
19
|
|
19
20
|
def [](key)
|
@@ -12,20 +12,6 @@ module Dor
|
|
12
12
|
# @param assign_doi [Boolean]
|
13
13
|
# @return [Cocina::Models::RequestDRO,Cocina::Models::RequestCollection,Cocina::Models::RequestAPO] the returned model
|
14
14
|
def register(params:, assign_doi: false)
|
15
|
-
json_str = register_response(params: params, assign_doi: assign_doi)
|
16
|
-
json = JSON.parse(json_str)
|
17
|
-
|
18
|
-
Cocina::Models.build(json)
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
# make the registration request to the server
|
24
|
-
# @param params [Hash] optional params (see dor-services-app)
|
25
|
-
# @param assign_doi [Boolean]
|
26
|
-
# @raise [UnexpectedResponse] on an unsuccessful response from the server
|
27
|
-
# @return [String] the raw JSON from the server
|
28
|
-
def register_response(params:, assign_doi:)
|
29
15
|
resp = connection.post do |req|
|
30
16
|
req.url "#{api_version}/objects"
|
31
17
|
req.headers['Content-Type'] = 'application/json'
|
@@ -34,9 +20,10 @@ module Dor
|
|
34
20
|
req.params[:assign_doi] = true if assign_doi
|
35
21
|
req.body = params.to_json
|
36
22
|
end
|
37
|
-
return resp.body if resp.success?
|
38
23
|
|
39
|
-
raise_exception_based_on_response!(resp)
|
24
|
+
raise_exception_based_on_response!(resp) unless resp.success?
|
25
|
+
|
26
|
+
build_cocina_from_response(resp)
|
40
27
|
end
|
41
28
|
end
|
42
29
|
end
|
@@ -5,6 +5,14 @@ module Dor
|
|
5
5
|
class Client
|
6
6
|
# @abstract API calls to a versioned endpoint
|
7
7
|
class VersionedService
|
8
|
+
EXCEPTION_CLASS = {
|
9
|
+
400 => BadRequestError,
|
10
|
+
401 => UnauthorizedResponse,
|
11
|
+
404 => NotFoundResponse,
|
12
|
+
409 => ConflictResponse,
|
13
|
+
412 => PreconditionFailedResponse
|
14
|
+
}.freeze
|
15
|
+
|
8
16
|
def initialize(connection:, version:)
|
9
17
|
@connection = connection
|
10
18
|
@api_version = version
|
@@ -19,24 +27,31 @@ module Dor
|
|
19
27
|
|
20
28
|
attr_reader :connection, :api_version
|
21
29
|
|
22
|
-
# rubocop:disable Metrics/MethodLength
|
23
30
|
def raise_exception_based_on_response!(response, object_identifier = nil)
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
data = if response.headers['content-type'] == 'application/json'
|
32
|
+
JSON.parse(response.body)
|
33
|
+
else
|
34
|
+
{}
|
35
|
+
end
|
36
|
+
exception_class = EXCEPTION_CLASS.fetch(response.status, UnexpectedResponse)
|
37
|
+
raise exception_class.new(response: response,
|
38
|
+
object_identifier: object_identifier,
|
39
|
+
errors: data.fetch('errors', []))
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_cocina_from_response(response)
|
43
|
+
cocina_object = Cocina::Models.build(JSON.parse(response.body))
|
44
|
+
Cocina::Models.with_metadata(cocina_object, response.headers['ETag'], created: date_from_header(response, 'X-Created-At'),
|
45
|
+
modified: date_from_header(response, 'Last-Modified'))
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_json_from_cocina(cocina_object)
|
49
|
+
Cocina::Models.without_metadata(cocina_object).to_json
|
50
|
+
end
|
51
|
+
|
52
|
+
def date_from_header(response, key)
|
53
|
+
response.headers[key]&.to_datetime
|
38
54
|
end
|
39
|
-
# rubocop:enable Metrics/MethodLength
|
40
55
|
end
|
41
56
|
end
|
42
57
|
end
|
data/lib/dor/services/client.rb
CHANGED
@@ -38,7 +38,26 @@ module Dor
|
|
38
38
|
|
39
39
|
# Error that is raised when the remote server returns some unexpected response
|
40
40
|
# this could be any 4xx or 5xx status (except the ones that are direct children of the Error class above)
|
41
|
-
class UnexpectedResponse < Error
|
41
|
+
class UnexpectedResponse < Error
|
42
|
+
# @param [Faraday::Response] response
|
43
|
+
# @param [String] object_identifier (nil)
|
44
|
+
# @param [Hash<String,Object>] errors (nil) the JSON-API errors object
|
45
|
+
# rubocop:disable Lint/MissingSuper
|
46
|
+
def initialize(response:, object_identifier: nil, errors: nil)
|
47
|
+
@response = response
|
48
|
+
@object_identifier = object_identifier
|
49
|
+
@errors = errors
|
50
|
+
end
|
51
|
+
# rubocop:enable Lint/MissingSuper
|
52
|
+
|
53
|
+
attr_accessor :errors
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
return errors.map { |e| "#{e['title']} (#{e['detail']})" }.join(', ') if errors.present?
|
57
|
+
|
58
|
+
ResponseErrorFormatter.format(response: @response, object_identifier: @object_identifier)
|
59
|
+
end
|
60
|
+
end
|
42
61
|
|
43
62
|
# Error that is raised when the remote server returns a 401 Unauthorized
|
44
63
|
class UnauthorizedResponse < UnexpectedResponse; end
|
@@ -46,6 +65,10 @@ module Dor
|
|
46
65
|
# Error that is raised when the remote server returns a 409 Conflict
|
47
66
|
class ConflictResponse < UnexpectedResponse; end
|
48
67
|
|
68
|
+
# Error that is raised when the remote server returns a 412 Precondition Failed.
|
69
|
+
# This occurs when you sent an etag with If-Match, but the etag didn't match the latest version
|
70
|
+
class PreconditionFailedResponse < UnexpectedResponse; end
|
71
|
+
|
49
72
|
# Error that is raised when the remote server returns a 400 Bad Request; apps should not retry the request
|
50
73
|
class BadRequestError < UnexpectedResponse; end
|
51
74
|
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dor-services-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 9.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Coyne
|
8
8
|
- Michael Giarlo
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-04-
|
12
|
+
date: 2022-04-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -37,14 +37,14 @@ dependencies:
|
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.
|
40
|
+
version: 0.75.0
|
41
41
|
type: :runtime
|
42
42
|
prerelease: false
|
43
43
|
version_requirements: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 0.
|
47
|
+
version: 0.75.0
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: deprecation
|
50
50
|
requirement: !ruby/object:Gem::Requirement
|
@@ -213,7 +213,7 @@ dependencies:
|
|
213
213
|
- - ">="
|
214
214
|
- !ruby/object:Gem::Version
|
215
215
|
version: '0'
|
216
|
-
description:
|
216
|
+
description:
|
217
217
|
email:
|
218
218
|
- jcoyne@justincoyne.com
|
219
219
|
- leftwing@alumni.rutgers.edu
|
@@ -262,7 +262,7 @@ homepage: https://github.com/sul-dlss/dor-services-client
|
|
262
262
|
licenses: []
|
263
263
|
metadata:
|
264
264
|
rubygems_mfa_required: 'true'
|
265
|
-
post_install_message:
|
265
|
+
post_install_message:
|
266
266
|
rdoc_options: []
|
267
267
|
require_paths:
|
268
268
|
- lib
|
@@ -280,8 +280,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
280
280
|
- !ruby/object:Gem::Version
|
281
281
|
version: '0'
|
282
282
|
requirements: []
|
283
|
-
rubygems_version: 3.
|
284
|
-
signing_key:
|
283
|
+
rubygems_version: 3.3.7
|
284
|
+
signing_key:
|
285
285
|
specification_version: 4
|
286
286
|
summary: A client for dor-services-app
|
287
287
|
test_files: []
|