folio_client 0.18.0 → 0.20.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 +91 -3
- data/Gemfile +1 -1
- data/Gemfile.lock +115 -77
- data/README.md +84 -5
- data/folio_client.gemspec +2 -1
- data/lib/folio_client/authenticator.rb +9 -12
- data/lib/folio_client/inventory.rb +51 -3
- data/lib/folio_client/job_status.rb +4 -0
- data/lib/folio_client/source_storage.rb +2 -6
- data/lib/folio_client/unexpected_response.rb +7 -7
- data/lib/folio_client/version.rb +1 -1
- data/lib/folio_client.rb +46 -24
- metadata +18 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ef1f093f7eb2cfcd38d85fc547d702a9768235b9a4e24f061653225e207978a9
|
|
4
|
+
data.tar.gz: ffe4c65db99fda6d3cece47f00bb84d490794382342ec2b4be6d4d2ff97a4f1e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 514d18193471517981408f5e1193cc13efa0640e3ad3176030aee72629a3b27b0f6ef9b5f9b36ca5197a9280180276d609a7ca0abddd56d5e9885bc6215f81dd
|
|
7
|
+
data.tar.gz: 885859bc1542aa0ceb2d7cf6c939851e2f9774db332f39c2d66b90773d8a6fea6278cf4267a969ece4e492e277deb51ca94337bf02d4395fb00c5a8da3692aa9
|
data/.rubocop.yml
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
plugins:
|
|
2
2
|
- rubocop-capybara
|
|
3
3
|
- rubocop-factory_bot
|
|
4
|
+
- rubocop-rspec_rails
|
|
4
5
|
- rubocop-performance
|
|
5
6
|
- rubocop-rspec
|
|
6
|
-
- rubocop-rspec_rails
|
|
7
7
|
|
|
8
8
|
AllCops:
|
|
9
|
-
TargetRubyVersion: 3.
|
|
9
|
+
TargetRubyVersion: 3.4
|
|
10
10
|
DisplayCopNames: true
|
|
11
11
|
SuggestExtensions: false
|
|
12
12
|
Exclude:
|
|
@@ -403,3 +403,91 @@ FactoryBot/ExcessiveCreateList: # new in 2.25
|
|
|
403
403
|
Enabled: true
|
|
404
404
|
Performance/StringBytesize: # new in 1.23
|
|
405
405
|
Enabled: true
|
|
406
|
+
|
|
407
|
+
Lint/ArrayLiteralInRegexp: # new in 1.71
|
|
408
|
+
Enabled: true
|
|
409
|
+
Lint/CopDirectiveSyntax: # new in 1.72
|
|
410
|
+
Enabled: true
|
|
411
|
+
Lint/RedundantTypeConversion: # new in 1.72
|
|
412
|
+
Enabled: true
|
|
413
|
+
Lint/SuppressedExceptionInNumberConversion: # new in 1.72
|
|
414
|
+
Enabled: true
|
|
415
|
+
Lint/UselessConstantScoping: # new in 1.72
|
|
416
|
+
Enabled: true
|
|
417
|
+
Style/HashSlice: # new in 1.71
|
|
418
|
+
Enabled: true
|
|
419
|
+
Style/RedundantFormat: # new in 1.72
|
|
420
|
+
Enabled: true
|
|
421
|
+
Performance/ZipWithoutBlock: # new in 1.24
|
|
422
|
+
Enabled: true
|
|
423
|
+
|
|
424
|
+
Lint/UselessDefaultValueArgument: # new in 1.76
|
|
425
|
+
Enabled: true
|
|
426
|
+
Lint/UselessOr: # new in 1.76
|
|
427
|
+
Enabled: true
|
|
428
|
+
Naming/PredicateMethod: # new in 1.76
|
|
429
|
+
Enabled: true
|
|
430
|
+
Style/ComparableBetween: # new in 1.74
|
|
431
|
+
Enabled: true
|
|
432
|
+
Style/EmptyStringInsideInterpolation: # new in 1.76
|
|
433
|
+
Enabled: true
|
|
434
|
+
Style/HashFetchChain: # new in 1.75
|
|
435
|
+
Enabled: true
|
|
436
|
+
Style/ItBlockParameter: # new in 1.75
|
|
437
|
+
Enabled: true
|
|
438
|
+
Style/RedundantArrayFlatten: # new in 1.76
|
|
439
|
+
Enabled: true
|
|
440
|
+
RSpec/IncludeExamples: # new in 3.6
|
|
441
|
+
Enabled: true
|
|
442
|
+
Capybara/FindAllFirst: # new in 2.22
|
|
443
|
+
Enabled: true
|
|
444
|
+
Capybara/NegationMatcherAfterVisit: # new in 2.22
|
|
445
|
+
Enabled: true
|
|
446
|
+
Gemspec/AttributeAssignment: # new in 1.77
|
|
447
|
+
Enabled: true
|
|
448
|
+
Layout/EmptyLinesAfterModuleInclusion: # new in 1.79
|
|
449
|
+
Enabled: true
|
|
450
|
+
Style/ArrayIntersectWithSingleElement: # new in 1.81
|
|
451
|
+
Enabled: true
|
|
452
|
+
Style/CollectionQuerying: # new in 1.77
|
|
453
|
+
Enabled: true
|
|
454
|
+
Style/EmptyClassDefinition: # new in 1.84
|
|
455
|
+
Enabled: true
|
|
456
|
+
Style/ModuleMemberExistenceCheck: # new in 1.82
|
|
457
|
+
Enabled: true
|
|
458
|
+
Style/NegativeArrayIndex: # new in 1.84
|
|
459
|
+
Enabled: true
|
|
460
|
+
Style/ReverseFind: # new in 1.84
|
|
461
|
+
Enabled: true
|
|
462
|
+
RSpecRails/HttpStatusNameConsistency: # new in 2.32
|
|
463
|
+
Enabled: true
|
|
464
|
+
RSpec/LeakyLocalVariable: # new in 3.8
|
|
465
|
+
Enabled: true
|
|
466
|
+
RSpec/Output: # new in 3.9
|
|
467
|
+
Enabled: true
|
|
468
|
+
Lint/DataDefineOverride: # new in 1.85
|
|
469
|
+
Enabled: true
|
|
470
|
+
Lint/UnreachablePatternBranch: # new in 1.85
|
|
471
|
+
Enabled: true
|
|
472
|
+
Style/FileOpen: # new in 1.85
|
|
473
|
+
Enabled: true
|
|
474
|
+
Style/MapJoin: # new in 1.85
|
|
475
|
+
Enabled: true
|
|
476
|
+
Style/OneClassPerFile: # new in 1.85
|
|
477
|
+
Enabled: true
|
|
478
|
+
Style/PartitionInsteadOfDoubleSelect: # new in 1.85
|
|
479
|
+
Enabled: true
|
|
480
|
+
Style/PredicateWithKind: # new in 1.85
|
|
481
|
+
Enabled: true
|
|
482
|
+
Style/ReduceToHash: # new in 1.85
|
|
483
|
+
Enabled: true
|
|
484
|
+
Style/RedundantMinMaxBy: # new in 1.85
|
|
485
|
+
Enabled: true
|
|
486
|
+
Style/RedundantStructKeywordInit: # new in 1.85
|
|
487
|
+
Enabled: true
|
|
488
|
+
Style/SelectByKind: # new in 1.85
|
|
489
|
+
Enabled: true
|
|
490
|
+
Style/SelectByRange: # new in 1.85
|
|
491
|
+
Enabled: true
|
|
492
|
+
Style/TallyMethod: # new in 1.85
|
|
493
|
+
Enabled: true
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,160 +1,198 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
folio_client (0.
|
|
4
|
+
folio_client (0.20.0)
|
|
5
5
|
activesupport (>= 4.2)
|
|
6
6
|
dry-monads
|
|
7
7
|
faraday
|
|
8
8
|
faraday-cookie_jar
|
|
9
9
|
marc
|
|
10
|
+
ostruct
|
|
10
11
|
zeitwerk
|
|
11
12
|
|
|
12
13
|
GEM
|
|
13
14
|
remote: https://rubygems.org/
|
|
14
15
|
specs:
|
|
15
|
-
activesupport (8.
|
|
16
|
+
activesupport (8.1.2)
|
|
16
17
|
base64
|
|
17
|
-
benchmark (>= 0.3)
|
|
18
18
|
bigdecimal
|
|
19
19
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
20
20
|
connection_pool (>= 2.2.5)
|
|
21
21
|
drb
|
|
22
22
|
i18n (>= 1.6, < 2)
|
|
23
|
+
json
|
|
23
24
|
logger (>= 1.4.2)
|
|
24
25
|
minitest (>= 5.1)
|
|
25
26
|
securerandom (>= 0.3)
|
|
26
27
|
tzinfo (~> 2.0, >= 2.0.5)
|
|
27
28
|
uri (>= 0.13.1)
|
|
28
|
-
addressable (2.8.
|
|
29
|
-
public_suffix (>= 2.0.2, <
|
|
30
|
-
ast (2.4.
|
|
31
|
-
base64 (0.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
connection_pool (2.5.0)
|
|
37
|
-
crack (1.0.0)
|
|
29
|
+
addressable (2.8.9)
|
|
30
|
+
public_suffix (>= 2.0.2, < 8.0)
|
|
31
|
+
ast (2.4.3)
|
|
32
|
+
base64 (0.3.0)
|
|
33
|
+
bigdecimal (4.0.1)
|
|
34
|
+
concurrent-ruby (1.3.6)
|
|
35
|
+
connection_pool (3.0.2)
|
|
36
|
+
crack (1.0.1)
|
|
38
37
|
bigdecimal
|
|
39
38
|
rexml
|
|
40
|
-
|
|
39
|
+
date (3.5.1)
|
|
40
|
+
debug (1.11.1)
|
|
41
|
+
irb (~> 1.10)
|
|
42
|
+
reline (>= 0.3.8)
|
|
43
|
+
diff-lcs (1.6.2)
|
|
41
44
|
docile (1.4.1)
|
|
42
45
|
domain_name (0.6.20240107)
|
|
43
|
-
drb (2.2.
|
|
44
|
-
dry-core (1.
|
|
46
|
+
drb (2.2.3)
|
|
47
|
+
dry-core (1.2.0)
|
|
45
48
|
concurrent-ruby (~> 1.0)
|
|
46
49
|
logger
|
|
47
50
|
zeitwerk (~> 2.6)
|
|
48
|
-
dry-monads (1.
|
|
51
|
+
dry-monads (1.9.0)
|
|
49
52
|
concurrent-ruby (~> 1.0)
|
|
50
53
|
dry-core (~> 1.1)
|
|
51
54
|
zeitwerk (~> 2.6)
|
|
52
|
-
|
|
55
|
+
erb (6.0.2)
|
|
56
|
+
faraday (2.14.1)
|
|
53
57
|
faraday-net_http (>= 2.0, < 3.5)
|
|
54
58
|
json
|
|
55
59
|
logger
|
|
56
|
-
faraday-cookie_jar (0.0.
|
|
60
|
+
faraday-cookie_jar (0.0.8)
|
|
57
61
|
faraday (>= 0.8.0)
|
|
58
|
-
http-cookie (
|
|
59
|
-
faraday-net_http (3.4.
|
|
60
|
-
net-http (
|
|
61
|
-
hashdiff (1.1
|
|
62
|
-
http-cookie (1.0
|
|
62
|
+
http-cookie (>= 1.0.0)
|
|
63
|
+
faraday-net_http (3.4.2)
|
|
64
|
+
net-http (~> 0.5)
|
|
65
|
+
hashdiff (1.2.1)
|
|
66
|
+
http-cookie (1.1.0)
|
|
63
67
|
domain_name (~> 0.5)
|
|
64
|
-
i18n (1.14.
|
|
68
|
+
i18n (1.14.8)
|
|
65
69
|
concurrent-ruby (~> 1.0)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
io-console (0.8.2)
|
|
71
|
+
irb (1.17.0)
|
|
72
|
+
pp (>= 0.6.0)
|
|
73
|
+
prism (>= 1.3.0)
|
|
74
|
+
rdoc (>= 4.0.0)
|
|
75
|
+
reline (>= 0.4.2)
|
|
76
|
+
json (2.19.1)
|
|
77
|
+
json-schema (6.2.0)
|
|
78
|
+
addressable (~> 2.8)
|
|
79
|
+
bigdecimal (>= 3.1, < 5)
|
|
80
|
+
language_server-protocol (3.17.0.5)
|
|
81
|
+
lint_roller (1.1.0)
|
|
82
|
+
logger (1.7.0)
|
|
83
|
+
marc (1.4.0)
|
|
70
84
|
nokogiri (~> 1.0)
|
|
71
85
|
rexml
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
mcp (0.8.0)
|
|
87
|
+
json-schema (>= 4.1)
|
|
88
|
+
minitest (6.0.2)
|
|
89
|
+
drb (~> 2.0)
|
|
90
|
+
prism (~> 1.5)
|
|
91
|
+
net-http (0.9.1)
|
|
92
|
+
uri (>= 0.11.1)
|
|
93
|
+
nokogiri (1.19.1-arm64-darwin)
|
|
78
94
|
racc (~> 1.4)
|
|
79
|
-
nokogiri (1.
|
|
95
|
+
nokogiri (1.19.1-x86_64-linux-gnu)
|
|
80
96
|
racc (~> 1.4)
|
|
81
|
-
|
|
82
|
-
|
|
97
|
+
ostruct (0.6.3)
|
|
98
|
+
parallel (1.27.0)
|
|
99
|
+
parser (3.3.10.2)
|
|
83
100
|
ast (~> 2.4.1)
|
|
84
101
|
racc
|
|
85
|
-
|
|
102
|
+
pp (0.6.3)
|
|
103
|
+
prettyprint
|
|
104
|
+
prettyprint (0.2.0)
|
|
105
|
+
prism (1.9.0)
|
|
106
|
+
psych (5.3.1)
|
|
107
|
+
date
|
|
108
|
+
stringio
|
|
109
|
+
public_suffix (7.0.5)
|
|
86
110
|
racc (1.8.1)
|
|
87
111
|
rainbow (3.1.1)
|
|
88
|
-
rake (13.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
112
|
+
rake (13.3.1)
|
|
113
|
+
rdoc (7.2.0)
|
|
114
|
+
erb
|
|
115
|
+
psych (>= 4.0.0)
|
|
116
|
+
tsort
|
|
117
|
+
regexp_parser (2.11.3)
|
|
118
|
+
reline (0.6.3)
|
|
119
|
+
io-console (~> 0.5)
|
|
120
|
+
rexml (3.4.4)
|
|
121
|
+
rspec (3.13.2)
|
|
92
122
|
rspec-core (~> 3.13.0)
|
|
93
123
|
rspec-expectations (~> 3.13.0)
|
|
94
124
|
rspec-mocks (~> 3.13.0)
|
|
95
|
-
rspec-core (3.13.
|
|
125
|
+
rspec-core (3.13.6)
|
|
96
126
|
rspec-support (~> 3.13.0)
|
|
97
|
-
rspec-expectations (3.13.
|
|
127
|
+
rspec-expectations (3.13.5)
|
|
98
128
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
99
129
|
rspec-support (~> 3.13.0)
|
|
100
|
-
rspec-mocks (3.13.
|
|
130
|
+
rspec-mocks (3.13.8)
|
|
101
131
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
102
132
|
rspec-support (~> 3.13.0)
|
|
103
|
-
rspec-support (3.13.
|
|
104
|
-
rubocop (1.
|
|
133
|
+
rspec-support (3.13.7)
|
|
134
|
+
rubocop (1.85.1)
|
|
105
135
|
json (~> 2.3)
|
|
106
|
-
language_server-protocol (
|
|
136
|
+
language_server-protocol (~> 3.17.0.2)
|
|
137
|
+
lint_roller (~> 1.1.0)
|
|
138
|
+
mcp (~> 0.6)
|
|
107
139
|
parallel (~> 1.10)
|
|
108
140
|
parser (>= 3.3.0.2)
|
|
109
141
|
rainbow (>= 2.2.2, < 4.0)
|
|
110
142
|
regexp_parser (>= 2.9.3, < 3.0)
|
|
111
|
-
rubocop-ast (>= 1.
|
|
143
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
112
144
|
ruby-progressbar (~> 1.7)
|
|
113
145
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
114
|
-
rubocop-ast (1.
|
|
115
|
-
parser (>= 3.3.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
rubocop (~> 1.
|
|
120
|
-
rubocop-
|
|
121
|
-
|
|
122
|
-
rubocop
|
|
123
|
-
rubocop-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
rubocop (
|
|
127
|
-
|
|
146
|
+
rubocop-ast (1.49.0)
|
|
147
|
+
parser (>= 3.3.7.2)
|
|
148
|
+
prism (~> 1.7)
|
|
149
|
+
rubocop-capybara (2.22.1)
|
|
150
|
+
lint_roller (~> 1.1)
|
|
151
|
+
rubocop (~> 1.72, >= 1.72.1)
|
|
152
|
+
rubocop-factory_bot (2.28.0)
|
|
153
|
+
lint_roller (~> 1.1)
|
|
154
|
+
rubocop (~> 1.72, >= 1.72.1)
|
|
155
|
+
rubocop-performance (1.26.1)
|
|
156
|
+
lint_roller (~> 1.1)
|
|
157
|
+
rubocop (>= 1.75.0, < 2.0)
|
|
158
|
+
rubocop-ast (>= 1.47.1, < 2.0)
|
|
159
|
+
rubocop-rspec (3.9.0)
|
|
160
|
+
lint_roller (~> 1.1)
|
|
161
|
+
rubocop (~> 1.81)
|
|
162
|
+
rubocop-rspec_rails (2.32.0)
|
|
163
|
+
lint_roller (~> 1.1)
|
|
164
|
+
rubocop (~> 1.72, >= 1.72.1)
|
|
165
|
+
rubocop-rspec (~> 3.5)
|
|
128
166
|
ruby-progressbar (1.13.0)
|
|
129
167
|
securerandom (0.4.1)
|
|
130
168
|
simplecov (0.22.0)
|
|
131
169
|
docile (~> 1.1)
|
|
132
170
|
simplecov-html (~> 0.11)
|
|
133
171
|
simplecov_json_formatter (~> 0.1)
|
|
134
|
-
simplecov-html (0.13.
|
|
172
|
+
simplecov-html (0.13.2)
|
|
135
173
|
simplecov_json_formatter (0.1.4)
|
|
174
|
+
stringio (3.2.0)
|
|
175
|
+
tsort (0.2.0)
|
|
136
176
|
tzinfo (2.0.6)
|
|
137
177
|
concurrent-ruby (~> 1.0)
|
|
138
|
-
unicode-display_width (3.
|
|
139
|
-
unicode-emoji (~> 4.
|
|
140
|
-
unicode-emoji (4.0
|
|
141
|
-
uri (1.
|
|
142
|
-
webmock (3.
|
|
178
|
+
unicode-display_width (3.2.0)
|
|
179
|
+
unicode-emoji (~> 4.1)
|
|
180
|
+
unicode-emoji (4.2.0)
|
|
181
|
+
uri (1.1.1)
|
|
182
|
+
webmock (3.26.1)
|
|
143
183
|
addressable (>= 2.8.0)
|
|
144
184
|
crack (>= 0.3.2)
|
|
145
185
|
hashdiff (>= 0.4.0, < 2.0.0)
|
|
146
|
-
zeitwerk (2.7.
|
|
186
|
+
zeitwerk (2.7.5)
|
|
147
187
|
|
|
148
188
|
PLATFORMS
|
|
149
189
|
arm64-darwin-23
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
x86_64-darwin-21
|
|
153
|
-
x86_64-darwin-22
|
|
190
|
+
arm64-darwin-24
|
|
191
|
+
arm64-darwin-25
|
|
154
192
|
x86_64-linux
|
|
155
193
|
|
|
156
194
|
DEPENDENCIES
|
|
157
|
-
|
|
195
|
+
debug
|
|
158
196
|
folio_client!
|
|
159
197
|
rake (~> 13.0)
|
|
160
198
|
rspec (~> 3.0)
|
|
@@ -168,4 +206,4 @@ DEPENDENCIES
|
|
|
168
206
|
webmock
|
|
169
207
|
|
|
170
208
|
BUNDLED WITH
|
|
171
|
-
|
|
209
|
+
4.0.7
|
data/README.md
CHANGED
|
@@ -25,10 +25,10 @@ require 'folio_client'
|
|
|
25
25
|
|
|
26
26
|
# this will configure the client and request an access token
|
|
27
27
|
client = FolioClient.configure(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
28
|
+
url: 'https://okapi-dev.stanford.edu',
|
|
29
|
+
login_params: { username: 'xxx', password: 'yyy' },
|
|
30
|
+
okapi_headers: { 'X-Okapi-Tenant': 'sul', 'User-Agent': 'FolioApiClient' }
|
|
31
|
+
)
|
|
32
32
|
|
|
33
33
|
response = client.get('/organizations/organizations', {query_string_param: 'abcdef'})
|
|
34
34
|
|
|
@@ -44,7 +44,6 @@ client = FolioClient.configure(
|
|
|
44
44
|
url: Settings.okapi.url,
|
|
45
45
|
login_params: Settings.okapi.login_params,
|
|
46
46
|
okapi_headers: Settings.okapi.headers,
|
|
47
|
-
legacy_auth: true # consumers should leave set to true (default) until /login-with-expiry endpoint enabled in Poppy
|
|
48
47
|
)
|
|
49
48
|
```
|
|
50
49
|
|
|
@@ -164,6 +163,86 @@ client.user_details(id: 'bbbadd51-c2f1-4107-a54d-52b39087725c')
|
|
|
164
163
|
=> {"username"=>"testing",
|
|
165
164
|
"id"=>"bbbadd51-c2f1-4107-a54d-52b39087725c",
|
|
166
165
|
"externalSystemId"=>"00324439", ... # same response as above, but for single user
|
|
166
|
+
|
|
167
|
+
# Get location details by UUID (useful for checking campusId when creating holdings)
|
|
168
|
+
# see https://s3.amazonaws.com/foliodocs/api/mod-inventory-storage/p/location.html#locations__id__get
|
|
169
|
+
client.fetch_location(location_id: 'd9cd0bed-1b49-4b5e-a7bd-064b8d177231')
|
|
170
|
+
=> {"id"=>"d9cd0bed-1b49-4b5e-a7bd-064b8d177231",
|
|
171
|
+
"name"=>"Miller General Stacks",
|
|
172
|
+
"code"=>"UA/CB/LC/GS",
|
|
173
|
+
"isActive"=>true,
|
|
174
|
+
"description"=>"The very general stacks of Miller",
|
|
175
|
+
"discoveryDisplayName"=>"Miller General",
|
|
176
|
+
"institutionId"=>"4b2a3d97-01c3-4ef3-98a5-ae4e853429b4",
|
|
177
|
+
"campusId"=>"b595d838-b1d5-409e-86ac-af3b41bde0be",
|
|
178
|
+
"libraryId"=>"e2889f93-92f2-4937-b944-5452a575367e",
|
|
179
|
+
"details"=>{"a"=>"b", "foo"=>"bar"},
|
|
180
|
+
"primaryServicePoint"=>"79faacf1-4ba4-42c7-8b2a-566b259e4641",
|
|
181
|
+
"servicePointIds"=>["79faacf1-4ba4-42c7-8b2a-566b259e4641"]}
|
|
182
|
+
|
|
183
|
+
# Get holdings records for an instance by HRID (useful for checking permanentLocationId and discoverySuppress)
|
|
184
|
+
# see https://github.com/folio-org/mod-search#search-api
|
|
185
|
+
client.fetch_holdings(hrid: 'in00000000067')
|
|
186
|
+
=> [{"id"=>"7f89e96c-478c-4ca2-bb85-0a1c5b0c6f3e",
|
|
187
|
+
"instanceId"=>"5108040a-65bc-40ed-bd50-265958301ce4",
|
|
188
|
+
"permanentLocationId"=>"d9cd0bed-1b49-4b5e-a7bd-064b8d177231",
|
|
189
|
+
"discoverySuppress"=>false,
|
|
190
|
+
"hrid"=>"ho00000000010",
|
|
191
|
+
"holdingsTypeId"=>"03c9c400-b9e3-4a07-ac0e-05ab470233ed",
|
|
192
|
+
"callNumber"=>"ABC 123"},
|
|
193
|
+
{"id"=>"8a89e96c-478c-4ca2-bb85-0a1c5b0c6f3f",
|
|
194
|
+
"instanceId"=>"5108040a-65bc-40ed-bd50-265958301ce4",
|
|
195
|
+
"permanentLocationId"=>"b595d838-b1d5-409e-86ac-af3b41bde0be",
|
|
196
|
+
"discoverySuppress"=>true,
|
|
197
|
+
"hrid"=>"ho00000000011",
|
|
198
|
+
"holdingsTypeId"=>"03c9c400-b9e3-4a07-ac0e-05ab470233ed",
|
|
199
|
+
"callNumber"=>"DEF 456"}]
|
|
200
|
+
|
|
201
|
+
# Update a holdings record for an instance HRID
|
|
202
|
+
holdings_record =
|
|
203
|
+
{ 'id' => '7f89e96c-478c-4ca2-bb85-0a1c5b0c6f3e',
|
|
204
|
+
'_version' => 1,
|
|
205
|
+
'sourceId' => 'f32d531e-df79-46b3-8932-cdd35f7a2264',
|
|
206
|
+
'hrid' => 'ah1994253_1',
|
|
207
|
+
'holdingsTypeId' => '5684e4a3-9279-4463-b6ee-20ae21bbec07',
|
|
208
|
+
'instanceId' => '54ec1f1a-d039-5a39-95f2-71df00061664',
|
|
209
|
+
'permanentLocationId' => '4573e824-9273-4f13-972f-cff7bf504217',
|
|
210
|
+
'effectiveLocationId' => '4573e824-9273-4f13-972f-cff7bf504217',
|
|
211
|
+
'discoverySuppress' => false }
|
|
212
|
+
client.update_holdings(holdings_id: '7f89e96c-478c-4ca2-bb85-0a1c5b0c6f3e', holdings_record:)
|
|
213
|
+
|
|
214
|
+
#Create a holdings record
|
|
215
|
+
holdings_record =
|
|
216
|
+
{ "instance_id" => "f1b301ce-f5d2-53b5-85eb-e4452bb5a591",
|
|
217
|
+
"permanent_location_id" => '1b14e21c-8d47-45c7-bc49-456a0086422b',
|
|
218
|
+
"source_id" => "f32d531e-df79-46b3-8932-cdd35f7a2264",
|
|
219
|
+
"holdings_type_id" => "996f93e2-5b5e-4cf2-9168-33ced1f95eed",
|
|
220
|
+
"discovery_suppress" => false }
|
|
221
|
+
client.create_holdings(holdings_record:)
|
|
222
|
+
=> {
|
|
223
|
+
"id" => "c65bb9dc-ebca-41fc-9c50-0d39085c1987",
|
|
224
|
+
"_version" => 1,
|
|
225
|
+
"sourceId" => "f32d531e-df79-46b3-8932-cdd35f7a2264",
|
|
226
|
+
"hrid" => "ho00000927052",
|
|
227
|
+
"holdingsTypeId" => "996f93e2-5b5e-4cf2-9168-33ced1f95eed",
|
|
228
|
+
"formerIds" => [],
|
|
229
|
+
"instanceId" => "54ec1f1a-d039-5a39-95f2-71df00061664",
|
|
230
|
+
"permanentLocationId" => "1b14e21c-8d47-45c7-bc49-456a0086422b",
|
|
231
|
+
"effectiveLocationId" => "1b14e21c-8d47-45c7-bc49-456a0086422b",
|
|
232
|
+
"electronicAccess" => [],
|
|
233
|
+
"administrativeNotes" => [],
|
|
234
|
+
"notes" => [],
|
|
235
|
+
"holdingsStatements" => [],
|
|
236
|
+
"holdingsStatementsForIndexes" => [],
|
|
237
|
+
"holdingsStatementsForSupplements" => [],
|
|
238
|
+
"discoverySuppress" => false,
|
|
239
|
+
"statisticalCodeIds" => [],
|
|
240
|
+
"metadata" =>
|
|
241
|
+
{"createdDate" => "2026-03-12T18:58:03.576+00:00",
|
|
242
|
+
"createdByUserId" => "709fdac6-d3f3-5784-8839-fe36ad6ed0b3",
|
|
243
|
+
"updatedDate" => "2026-03-12T18:58:03.576+00:00",
|
|
244
|
+
"updatedByUserId" => "709fdac6-d3f3-5784-8839-fe36ad6ed0b3"}
|
|
245
|
+
}
|
|
167
246
|
```
|
|
168
247
|
|
|
169
248
|
## Development
|
data/folio_client.gemspec
CHANGED
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
spec.summary = 'Interface for interacting with the Folio ILS API.'
|
|
14
14
|
spec.description = 'This provides API interaction with the Folio ILS API'
|
|
15
15
|
spec.homepage = 'https://github.com/sul-dlss/folio_client'
|
|
16
|
-
spec.required_ruby_version = '>= 3.
|
|
16
|
+
spec.required_ruby_version = '>= 3.4'
|
|
17
17
|
|
|
18
18
|
spec.metadata['homepage_uri'] = spec.homepage
|
|
19
19
|
spec.metadata['source_code_uri'] = 'https://github.com/sul-dlss/folio_client'
|
|
@@ -36,6 +36,7 @@ Gem::Specification.new do |spec|
|
|
|
36
36
|
spec.add_dependency 'faraday'
|
|
37
37
|
spec.add_dependency 'faraday-cookie_jar'
|
|
38
38
|
spec.add_dependency 'marc'
|
|
39
|
+
spec.add_dependency 'ostruct'
|
|
39
40
|
spec.add_dependency 'zeitwerk'
|
|
40
41
|
|
|
41
42
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
@@ -8,29 +8,26 @@ class FolioClient
|
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
# Request an access_token
|
|
11
|
-
def token
|
|
11
|
+
def token
|
|
12
12
|
response = FolioClient.connection.post(login_endpoint, FolioClient.config.login_params.to_json)
|
|
13
13
|
|
|
14
14
|
UnexpectedResponse.call(response) unless response.success?
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
if FolioClient.config.legacy_auth
|
|
18
|
-
JSON.parse(response.body)['okapiToken']
|
|
19
|
-
else
|
|
20
|
-
access_cookie = FolioClient.cookie_jar.cookies.find { |cookie| cookie.name == 'folioAccessToken' }
|
|
16
|
+
access_cookie = FolioClient.cookie_jar.cookies.find { |cookie| cookie.name == 'folioAccessToken' }
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
# NOTE: The client typically delegates raising exceptions (based on HTTP
|
|
19
|
+
# responses) to the UnexpectedResponse class, but this call in
|
|
20
|
+
# Authenticator is a one-off, unlike any other in the app, so we
|
|
21
|
+
# allow it to customize its exception handling.
|
|
22
|
+
raise UnauthorizedError, "Problem with folioAccessToken cookie: #{response.headers}, #{response.body}" unless access_cookie
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
end
|
|
24
|
+
access_cookie.value
|
|
26
25
|
end
|
|
27
26
|
|
|
28
27
|
private
|
|
29
28
|
|
|
30
29
|
def login_endpoint
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
'/authn/login'
|
|
30
|
+
'/authn/login-with-expiry'
|
|
34
31
|
end
|
|
35
32
|
end
|
|
36
33
|
end
|
|
@@ -25,7 +25,7 @@ class FolioClient
|
|
|
25
25
|
def fetch_external_id(hrid:)
|
|
26
26
|
instance_response = client.get('/search/instances', { query: "hrid==#{hrid}" })
|
|
27
27
|
record_count = instance_response['totalRecords']
|
|
28
|
-
raise ResourceNotFound, "No matching instance found for #{hrid}" if
|
|
28
|
+
raise ResourceNotFound, "No matching instance found for #{hrid}" if instance_response['totalRecords'].zero?
|
|
29
29
|
raise MultipleResourcesFound, "Expected 1 record for #{hrid}, but found #{record_count}" if record_count > 1
|
|
30
30
|
|
|
31
31
|
instance_response.dig('instances', 0, 'id')
|
|
@@ -50,10 +50,10 @@ class FolioClient
|
|
|
50
50
|
# @param status_id [String] uuid for an instance status code
|
|
51
51
|
# @return true if instance status matches the uuid param, false otherwise
|
|
52
52
|
# @raise [ResourceNotFound] if search by instance HRID returns 0 results
|
|
53
|
-
def has_instance_status?(hrid:, status_id:) # rubocop:disable Naming/
|
|
53
|
+
def has_instance_status?(hrid:, status_id:) # rubocop:disable Naming/PredicatePrefix
|
|
54
54
|
# get the instance record and its statusId
|
|
55
55
|
instance = client.get('/inventory/instances', { query: "hrid==#{hrid}" })
|
|
56
|
-
raise ResourceNotFound, "No matching instance found for #{hrid}" if
|
|
56
|
+
raise ResourceNotFound, "No matching instance found for #{hrid}" if instance['totalRecords'].zero?
|
|
57
57
|
|
|
58
58
|
instance_status_id = instance.dig('instances', 0, 'statusId')
|
|
59
59
|
|
|
@@ -64,6 +64,54 @@ class FolioClient
|
|
|
64
64
|
false
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
# Get location details by UUID
|
|
68
|
+
# @param location_id [String] UUID of the location
|
|
69
|
+
# @return [Hash] location data including campusId and other location information
|
|
70
|
+
# @raise [ResourceNotFound] if location with the given UUID is not found
|
|
71
|
+
def fetch_location(location_id:)
|
|
72
|
+
client.get("/locations/#{location_id}")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Get holdings records for an instance by HRID
|
|
76
|
+
# @see https://s3.amazonaws.com/foliodocs/api/mod-inventory-storage/p/inventory-view.html
|
|
77
|
+
# @param hrid [String] instance HRID
|
|
78
|
+
# @return [Array<Hash>] array of holdings records with permanentLocationId, _version, discoverySuppress, and other fields
|
|
79
|
+
def fetch_holdings(hrid:)
|
|
80
|
+
instance_uuid = fetch_external_id(hrid: hrid)
|
|
81
|
+
instance_response = client.get('/inventory-view/instances', { query: "id==#{instance_uuid}" })
|
|
82
|
+
|
|
83
|
+
instance_response.dig('instances', 0, 'holdingsRecords') || []
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Put an updated holdings record
|
|
87
|
+
# @see https://s3.amazonaws.com/foliodocs/api/mod-inventory/p/inventory.html#inventory_holdings__holdingsid__put
|
|
88
|
+
# @param holdings_id [String] UUID of the holdings record to update
|
|
89
|
+
# @param holdings_record [Hash] holdings record
|
|
90
|
+
# @raise [ResourceNotFound] if holdings record with the given UUID is not found
|
|
91
|
+
# @raise [BadRequestError] may occur if the update includes invalid fields or values
|
|
92
|
+
# @raise [UnexpectedResponse] if the API returns some other error response
|
|
93
|
+
def update_holdings(holdings_id:, holdings_record:)
|
|
94
|
+
client.put("/inventory/holdings/#{holdings_id}", holdings_record, exception_subject: "holdings record with ID #{holdings_id}")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Post a new holdings record
|
|
98
|
+
# @param holdings_record [Hash] holdings record
|
|
99
|
+
# @return [Hash] the created holdings record, including its id and other fields
|
|
100
|
+
# @see https://s3.amazonaws.com/foliodocs/api/mod-inventory-storage/p/holdings-storage.html#holdings_storage_holdings_post
|
|
101
|
+
def create_holdings(holdings_record:)
|
|
102
|
+
required = %w[instance_id permanent_location_id source_id holdings_type_id]
|
|
103
|
+
missing = required.select { |field| !holdings_record.key?(field) || holdings_record[field].blank? }
|
|
104
|
+
raise ArgumentError, "Missing required fields: #{missing.join(', ')}" if missing.any?
|
|
105
|
+
|
|
106
|
+
client.post('/holdings-storage/holdings', {
|
|
107
|
+
instanceId: holdings_record['instance_id'],
|
|
108
|
+
permanentLocationId: holdings_record['permanent_location_id'],
|
|
109
|
+
sourceId: holdings_record['source_id'],
|
|
110
|
+
holdingsTypeId: holdings_record['holdings_type_id'],
|
|
111
|
+
discoverySuppress: false
|
|
112
|
+
})
|
|
113
|
+
end
|
|
114
|
+
|
|
67
115
|
private
|
|
68
116
|
|
|
69
117
|
def client
|
|
@@ -98,6 +98,10 @@ class FolioClient
|
|
|
98
98
|
def check_not_found(result, index, max_checks)
|
|
99
99
|
return unless result.failure? && result.failure == :not_found && index > max_checks
|
|
100
100
|
|
|
101
|
+
# NOTE: The client typically delegates raising exceptions (based on HTTP
|
|
102
|
+
# responses) to the UnexpectedResponse class, but the interaction in
|
|
103
|
+
# JobStatus is more complex due to waits/loops, so we allow this
|
|
104
|
+
# class to do some of its own exception handling.
|
|
101
105
|
raise ResourceNotFound,
|
|
102
106
|
"Job #{job_execution_id} not found after #{index} retries. The data import job may still have completed."
|
|
103
107
|
end
|
|
@@ -21,7 +21,7 @@ class FolioClient
|
|
|
21
21
|
"Expected 1 record for #{instance_hrid}, but found #{record_count}"
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
-
response_hash
|
|
24
|
+
response_hash.dig('sourceRecords', 0, 'parsedRecord', 'content')
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
# get marc bib data as MARCXML from folio given an instance HRID
|
|
@@ -30,9 +30,7 @@ class FolioClient
|
|
|
30
30
|
# @return [String] MARCXML string
|
|
31
31
|
# @raise [ResourceNotFound]
|
|
32
32
|
# @raise [MultipleResourcesFound]
|
|
33
|
-
# rubocop:disable Metrics/MethodLength
|
|
34
|
-
# rubocop:disable Metrics/AbcSize
|
|
35
|
-
def fetch_marc_xml(instance_hrid: nil, barcode: nil)
|
|
33
|
+
def fetch_marc_xml(instance_hrid: nil, barcode: nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
36
34
|
if barcode.nil? && instance_hrid.nil?
|
|
37
35
|
raise ArgumentError,
|
|
38
36
|
'Either a barcode or a Folio instance HRID must be provided'
|
|
@@ -62,8 +60,6 @@ class FolioClient
|
|
|
62
60
|
updated_marc.fields << MARC::ControlField.new('003', 'FOLIO')
|
|
63
61
|
updated_marc.to_xml.to_s
|
|
64
62
|
end
|
|
65
|
-
# rubocop:enable Metrics/MethodLength
|
|
66
|
-
# rubocop:enable Metrics/AbcSize
|
|
67
63
|
|
|
68
64
|
private
|
|
69
65
|
|
|
@@ -4,16 +4,18 @@ class FolioClient
|
|
|
4
4
|
# Handles unexpected responses when communicating with Folio
|
|
5
5
|
class UnexpectedResponse
|
|
6
6
|
# @param [Faraday::Response] response
|
|
7
|
-
# rubocop:disable Metrics/MethodLength
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
def self.call(response, **kwargs) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
8
|
+
subject = kwargs.fetch(:exception_subject, 'resource')
|
|
9
|
+
|
|
10
10
|
case response.status
|
|
11
|
+
when 400
|
|
12
|
+
raise BadRequestError, "Bad request for #{subject}: #{response.body}"
|
|
11
13
|
when 401
|
|
12
14
|
raise UnauthorizedError, "There was a problem with the access token: #{response.body}"
|
|
13
15
|
when 403
|
|
14
16
|
raise ForbiddenError, "The operation requires privileges which the client does not have: #{response.body}"
|
|
15
17
|
when 404
|
|
16
|
-
raise ResourceNotFound, "Endpoint not found or
|
|
18
|
+
raise ResourceNotFound, "Endpoint not found or #{subject} does not exist: #{response.body}"
|
|
17
19
|
when 409
|
|
18
20
|
raise ConflictError, "Resource cannot be updated: #{response.body}"
|
|
19
21
|
when 422
|
|
@@ -21,10 +23,8 @@ class FolioClient
|
|
|
21
23
|
when 500
|
|
22
24
|
raise ServiceUnavailable, "The remote server returned an internal server error: #{response.body}"
|
|
23
25
|
else
|
|
24
|
-
raise
|
|
26
|
+
raise Error, "Unexpected response: #{response.status} #{response.body}"
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
end
|
|
28
|
-
# rubocop:enable Metrics/MethodLength
|
|
29
|
-
# rubocop:enable Metrics/AbcSize
|
|
30
30
|
end
|
data/lib/folio_client/version.rb
CHANGED
data/lib/folio_client.rb
CHANGED
|
@@ -41,6 +41,9 @@ class FolioClient
|
|
|
41
41
|
# Error raised when the Folio API returns a 409 Conflict
|
|
42
42
|
class ConflictError < Error; end
|
|
43
43
|
|
|
44
|
+
# Error raised when the Folio API returns a 400 Bad Request
|
|
45
|
+
class BadRequestError < Error; end
|
|
46
|
+
|
|
44
47
|
DEFAULT_HEADERS = {
|
|
45
48
|
accept: 'application/json, text/plain',
|
|
46
49
|
content_type: 'application/json'
|
|
@@ -50,9 +53,8 @@ class FolioClient
|
|
|
50
53
|
# @param url [String] the folio API URL
|
|
51
54
|
# @param login_params [Hash] the folio client login params (username:, password:)
|
|
52
55
|
# @param okapi_headers [Hash] the okapi specific headers to add (X-Okapi-Tenant:, User-Agent:)
|
|
53
|
-
# @param legacy_auth [Boolean] true to use legacy /login rather than Poppy /login-with-expiry endpoint
|
|
54
56
|
# @return [FolioClient] the configured Singleton class
|
|
55
|
-
def configure(url:, login_params:, okapi_headers:, timeout: default_timeout,
|
|
57
|
+
def configure(url:, login_params:, okapi_headers:, timeout: default_timeout, **)
|
|
56
58
|
# rubocop:disable Style/OpenStructUse
|
|
57
59
|
instance.config = OpenStruct.new(
|
|
58
60
|
# For the initial token, use a dummy value to avoid hitting any APIs
|
|
@@ -69,20 +71,19 @@ class FolioClient
|
|
|
69
71
|
url: url,
|
|
70
72
|
login_params: login_params,
|
|
71
73
|
okapi_headers: okapi_headers,
|
|
72
|
-
timeout: timeout
|
|
73
|
-
legacy_auth: legacy_auth # default true until we have new token endpoint enabled in Poppy
|
|
74
|
+
timeout: timeout
|
|
74
75
|
)
|
|
75
76
|
# rubocop:enable Style/OpenStructUse
|
|
76
77
|
|
|
77
78
|
self
|
|
78
79
|
end
|
|
79
80
|
|
|
80
|
-
delegate :config, :connection, :cookie_jar, :data_import, :default_timeout,
|
|
81
|
-
:edit_marc_json, :fetch_external_id, :fetch_hrid,
|
|
82
|
-
:fetch_instance_info, :fetch_marc_hash, :fetch_marc_xml,
|
|
81
|
+
delegate :config, :connection, :cookie_jar, :create_holdings, :data_import, :default_timeout,
|
|
82
|
+
:edit_marc_json, :fetch_external_id, :fetch_holdings, :fetch_hrid,
|
|
83
|
+
:fetch_instance_info, :fetch_location, :fetch_marc_hash, :fetch_marc_xml,
|
|
83
84
|
:force_token_refresh!, :get, :has_instance_status?,
|
|
84
85
|
:http_get_headers, :http_post_and_put_headers, :interface_details,
|
|
85
|
-
:job_profiles, :organization_interfaces, :organizations, :users,
|
|
86
|
+
:job_profiles, :organization_interfaces, :organizations, :update_holdings, :users,
|
|
86
87
|
:user_details, :post, :put, to: :instance
|
|
87
88
|
end
|
|
88
89
|
|
|
@@ -91,6 +92,7 @@ class FolioClient
|
|
|
91
92
|
# Send an authenticated get request
|
|
92
93
|
# @param path [String] the path to the Folio API request
|
|
93
94
|
# @param params [Hash] params to get to the API
|
|
95
|
+
# @return [Hash, nil] the parsed response body or nil
|
|
94
96
|
def get(path, params = {})
|
|
95
97
|
response = with_token_refresh_when_unauthorized do
|
|
96
98
|
connection.get(path, params, { 'x-okapi-token': config.token })
|
|
@@ -98,16 +100,14 @@ class FolioClient
|
|
|
98
100
|
|
|
99
101
|
UnexpectedResponse.call(response) unless response.success?
|
|
100
102
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
JSON.parse(response.body)
|
|
103
|
+
JSON.parse(response.body) if response.body.present?
|
|
104
104
|
end
|
|
105
105
|
|
|
106
106
|
# Send an authenticated post request
|
|
107
107
|
# If the body is JSON, it will be automatically serialized
|
|
108
108
|
# @param path [String] the path to the Folio API request
|
|
109
109
|
# @param body [Object] body to post to the API as JSON
|
|
110
|
-
#
|
|
110
|
+
# @return [Hash, nil] the parsed response body or nil
|
|
111
111
|
def post(path, body = nil, content_type: 'application/json')
|
|
112
112
|
req_body = content_type == 'application/json' ? body&.to_json : body
|
|
113
113
|
response = with_token_refresh_when_unauthorized do
|
|
@@ -120,18 +120,15 @@ class FolioClient
|
|
|
120
120
|
|
|
121
121
|
UnexpectedResponse.call(response) unless response.success?
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
JSON.parse(response.body)
|
|
123
|
+
JSON.parse(response.body) if response.body.present?
|
|
126
124
|
end
|
|
127
|
-
# rubocop:enable Metrics/MethodLength
|
|
128
125
|
|
|
129
126
|
# Send an authenticated put request
|
|
130
127
|
# If the body is JSON, it will be automatically serialized
|
|
131
128
|
# @param path [String] the path to the Folio API request
|
|
132
129
|
# @param body [Object] body to put to the API as JSON
|
|
133
|
-
#
|
|
134
|
-
def put(path, body = nil, content_type: 'application/json')
|
|
130
|
+
# @return [Hash, nil] the parsed response body or nil
|
|
131
|
+
def put(path, body = nil, content_type: 'application/json', **exception_args)
|
|
135
132
|
req_body = content_type == 'application/json' ? body&.to_json : body
|
|
136
133
|
response = with_token_refresh_when_unauthorized do
|
|
137
134
|
req_headers = {
|
|
@@ -141,13 +138,10 @@ class FolioClient
|
|
|
141
138
|
connection.put(path, req_body, req_headers)
|
|
142
139
|
end
|
|
143
140
|
|
|
144
|
-
UnexpectedResponse.call(response) unless response.success?
|
|
145
|
-
|
|
146
|
-
return nil if response.body.blank?
|
|
141
|
+
UnexpectedResponse.call(response, **exception_args) unless response.success?
|
|
147
142
|
|
|
148
|
-
JSON.parse(response.body)
|
|
143
|
+
JSON.parse(response.body) if response.body.present?
|
|
149
144
|
end
|
|
150
|
-
# rubocop:enable Metrics/MethodLength
|
|
151
145
|
|
|
152
146
|
# the base connection to the Folio API
|
|
153
147
|
def connection
|
|
@@ -188,6 +182,34 @@ class FolioClient
|
|
|
188
182
|
.fetch_instance_info(...)
|
|
189
183
|
end
|
|
190
184
|
|
|
185
|
+
# @see Inventory#fetch_location
|
|
186
|
+
def fetch_location(...)
|
|
187
|
+
Inventory
|
|
188
|
+
.new
|
|
189
|
+
.fetch_location(...)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# @see Inventory#fetch_holdings
|
|
193
|
+
def fetch_holdings(...)
|
|
194
|
+
Inventory
|
|
195
|
+
.new
|
|
196
|
+
.fetch_holdings(...)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# @see Inventory#update_holdings
|
|
200
|
+
def update_holdings(...)
|
|
201
|
+
Inventory
|
|
202
|
+
.new
|
|
203
|
+
.update_holdings(...)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# @see Inventory#create_holdings
|
|
207
|
+
def create_holdings(...)
|
|
208
|
+
Inventory
|
|
209
|
+
.new
|
|
210
|
+
.create_holdings(...)
|
|
211
|
+
end
|
|
212
|
+
|
|
191
213
|
# @see SourceStorage#fetch_marc_hash
|
|
192
214
|
def fetch_marc_hash(...)
|
|
193
215
|
SourceStorage
|
|
@@ -203,7 +225,7 @@ class FolioClient
|
|
|
203
225
|
end
|
|
204
226
|
|
|
205
227
|
# @see Inventory#has_instance_status?
|
|
206
|
-
def has_instance_status?(...) # rubocop:disable Naming/
|
|
228
|
+
def has_instance_status?(...) # rubocop:disable Naming/PredicatePrefix
|
|
207
229
|
Inventory
|
|
208
230
|
.new
|
|
209
231
|
.has_instance_status?(...)
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: folio_client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.20.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Mangiafico
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 2026-03-13 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: activesupport
|
|
@@ -79,6 +79,20 @@ dependencies:
|
|
|
79
79
|
- - ">="
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
81
|
version: '0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: ostruct
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0'
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
82
96
|
- !ruby/object:Gem::Dependency
|
|
83
97
|
name: zeitwerk
|
|
84
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -274,14 +288,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
274
288
|
requirements:
|
|
275
289
|
- - ">="
|
|
276
290
|
- !ruby/object:Gem::Version
|
|
277
|
-
version: 3.
|
|
291
|
+
version: '3.4'
|
|
278
292
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
279
293
|
requirements:
|
|
280
294
|
- - ">="
|
|
281
295
|
- !ruby/object:Gem::Version
|
|
282
296
|
version: '0'
|
|
283
297
|
requirements: []
|
|
284
|
-
rubygems_version: 3.6.
|
|
298
|
+
rubygems_version: 3.6.2
|
|
285
299
|
specification_version: 4
|
|
286
300
|
summary: Interface for interacting with the Folio ILS API.
|
|
287
301
|
test_files: []
|