folio_api_client 0.2.0 → 0.4.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: b1529c6d23ad243ce9503b24965a0afc4db6abd28a6cea7aae1000b42b5a19b0
4
- data.tar.gz: 8da619e1c7614fe9bf46951af5ee6c086467ec90869d0f32ba9803584b65487a
3
+ metadata.gz: b95e817f47b4694776baae831bcad7784810d06e7533577f27f8bcf4ea216b06
4
+ data.tar.gz: 63291ad25685d7c4ba71dd2399104b8925241da84eca2483f8bd63b4567b4454
5
5
  SHA512:
6
- metadata.gz: c6196344ec464f39dfdd0b44dbd269f3b949a630c7a41d449961a73091f494ad1d49edff1eb39d2f79b4d36ee0b9f6456257cb2ca645a4d8d1a4c8f0b3c50cd0
7
- data.tar.gz: 064356b0fe0d418128ae36d101005229d3eb766f89a62456a6b024bedb5a9d748e42335177918985c34a2bef7ed4a0168c54f38b6bea58a5fd2ed3b0508e86f4
6
+ metadata.gz: '018541167173b30bbf0c938c10465888581fd87d8c64885fd59dfcc3ea4a2305e93d75533f55c752b7eb495ee2b72be7b8514246caffe7bdebbe56b18f5f44ee'
7
+ data.tar.gz: 7812af3dbf43c33aa37c490e8a0a084de82842b64bcdc86571c0eb9e713ad293884f7ff03098d26d15acd75bbcb4a73a89d7f2c2d4eee6e1f32eccf1233405bf
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2025 The Trustees of Columbia University in the City of New York
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md CHANGED
@@ -42,6 +42,20 @@ client.get(path, params)
42
42
  client.post(path, body, content_type: 'application/json'))
43
43
  client.put(path, body, content_type: 'application/json'))
44
44
  client.delete(path, body, content_type: 'application/json'))
45
+
46
+ # Other convenience methods:
47
+
48
+ client.find_item_record(barcode: 'some-barcode')
49
+ client.find_location_record(location_id: 'some-location-id')
50
+ client.find_holdings_record(holdings_record_id: 'some-holdings-record-id')
51
+ client.find_instance_record(instance_record_id: 'some-instance-record-id')
52
+ client.find_instance_record(instance_record_hrid: 'some-instance-record-hrid')
53
+ client.find_source_record(instance_record_id: 'some-instance-record-id')
54
+ client.find_source_record(instance_record_hrid: 'some-instance-record-hrid')
55
+
56
+ # Convert a FOLIO MARC source record to a marc gem MARC::Record object:
57
+ source_record = client.find_source_record(instance_record_id: 'some-instance-record-id')
58
+ marc_record = MARC::Record.new_from_hash(source_record['parsedRecord']['content'])
45
59
  ```
46
60
 
47
61
  See [https://dev.folio.org/reference/api/](https://dev.folio.org/reference/api/) for the full list of available FOLIO API endpoints.
@@ -4,5 +4,6 @@ class FolioApiClient
4
4
  module Exceptions
5
5
  class Error < StandardError; end
6
6
  class UnexpectedMultipleRecordsFoundError < Error; end
7
+ class MissingQueryFieldError < Error; end
7
8
  end
8
9
  end
@@ -11,28 +11,71 @@ class FolioApiClient
11
11
  'Only expected one item with this barcode, but found more than one.'
12
12
  end
13
13
 
14
- item_record_id = item_search_results.first['id']
15
- self.get("/item-storage/items/#{item_record_id}")
14
+ item_search_results.first
16
15
  end
17
16
 
18
17
  def find_location_record(location_id:)
19
18
  self.get("/locations/#{location_id}")
20
19
  end
21
20
 
21
+ def find_loan_type_record(loan_type_id:)
22
+ self.get("/loan-types/#{loan_type_id}")
23
+ end
24
+
22
25
  def find_holdings_record(holdings_record_id:)
23
26
  self.get("/holdings-storage/holdings/#{holdings_record_id}")
24
27
  end
25
28
 
26
- def find_instance_record(instance_record_id:)
27
- self.get("/instance-storage/instances/#{instance_record_id}")
29
+ def find_instance_record(instance_record_id: nil, instance_record_hrid: nil)
30
+ instance_search_results = self.get(
31
+ '/instance-storage/instances',
32
+ instance_record_query(instance_record_id: instance_record_id, instance_record_hrid: instance_record_hrid)
33
+ )['instances']
34
+ return nil if instance_search_results.empty?
35
+
36
+ if instance_search_results.length > 1
37
+ raise FolioApiClient::Exceptions::UnexpectedMultipleRecordsFoundError,
38
+ 'Only expected one instance with this '\
39
+ "#{instance_record_id ? 'instance_record_id' : 'instance_record_hrid'}, "\
40
+ 'but found more than one.'
41
+ end
42
+
43
+ instance_search_results.first
28
44
  end
29
45
 
30
- def find_marc_record(instance_record_id:)
31
- source_record_search_results = self.get('/source-storage/source-records', { instanceId: instance_record_id })
46
+ # Find a source record by its instance record id or instance record hrid.
47
+ # @return [Hash] A Source Record (which can hold data for a MARC record).
48
+ def find_source_record(instance_record_id: nil, instance_record_hrid: nil)
49
+ source_record_search_results = self.get(
50
+ '/source-storage/source-records',
51
+ source_record_query(instance_record_id: instance_record_id, instance_record_hrid: instance_record_hrid)
52
+ )
32
53
  return nil if source_record_search_results['totalRecords'].zero?
33
54
 
34
- bib_record_marc_hash = source_record_search_results['sourceRecords'].first['parsedRecord']['content']
35
- MARC::Record.new_from_hash(bib_record_marc_hash)
55
+ if source_record_search_results['totalRecords'] > 1
56
+ raise FolioApiClient::Exceptions::UnexpectedMultipleRecordsFoundError,
57
+ 'Only expected one record with this '\
58
+ "#{instance_record_id ? 'instance_record_id' : 'instance_record_hrid'}, "\
59
+ 'but found more than one.'
60
+ end
61
+
62
+ source_record_search_results['sourceRecords'].first
63
+ end
64
+
65
+ def source_record_query(instance_record_id: nil, instance_record_hrid: nil)
66
+ return { instanceId: instance_record_id } if instance_record_id
67
+ return { instanceHrid: instance_record_hrid } if instance_record_hrid
68
+
69
+ raise FolioApiClient::Exceptions::MissingQueryFieldError,
70
+ 'Missing query field. Must supply either an instance_record_id or instance_record_hrid.'
71
+ end
72
+
73
+ def instance_record_query(instance_record_id: nil, instance_record_hrid: nil)
74
+ return { query: "id==#{instance_record_id}", limit: 2 } if instance_record_id
75
+ return { query: "hrid==#{instance_record_hrid}", limit: 2 } if instance_record_hrid
76
+
77
+ raise FolioApiClient::Exceptions::MissingQueryFieldError,
78
+ 'Missing query field. Must supply either an instance_record_id or instance_record_hrid.'
36
79
  end
37
80
  end
38
81
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class FolioApiClient
4
- VERSION = '0.2.0'
4
+ VERSION = '0.4.0'
5
5
  end
@@ -38,7 +38,7 @@ class FolioApiClient
38
38
  end
39
39
 
40
40
  def retrieve_new_auth_token
41
- response = connection.post('/authn/login', { username: config.username, password: config.password }.to_json)
41
+ response = connection.post('/authn/login', JSON.generate({ username: config.username, password: config.password }))
42
42
  response_data = JSON.parse(response.body)
43
43
  response_data['okapiToken']
44
44
  end
@@ -68,12 +68,12 @@ class FolioApiClient
68
68
  end
69
69
 
70
70
  def exec_request_with_body(method, path, body = nil, content_type: 'application/json')
71
- body = body.to_json if content_type == 'application/json' && !body.is_a?(String)
71
+ body = JSON.generate(body) if content_type == 'application/json' && !body.is_a?(String)
72
72
  response = with_token_refresh_attempt_when_unauthorized do
73
73
  connection.send(method, path, body, { 'x-okapi-token': config.token, 'content-type': content_type })
74
74
  end
75
75
 
76
- response.body.nil? ? nil : JSON.parse(response.body)
76
+ response.body.nil? || response.body == '' ? nil : JSON.parse(response.body)
77
77
  end
78
78
 
79
79
  def post(path, body = nil, content_type: 'application/json')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: folio_api_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric O'Hanlon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-04-30 00:00:00.000000000 Z
11
+ date: 2025-06-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -63,6 +63,7 @@ files:
63
63
  - ".rspec"
64
64
  - ".rubocop.yml"
65
65
  - ".ruby-version"
66
+ - LICENSE
66
67
  - README.md
67
68
  - Rakefile
68
69
  - lib/folio_api_client.rb
@@ -71,7 +72,8 @@ files:
71
72
  - lib/folio_api_client/finders.rb
72
73
  - lib/folio_api_client/version.rb
73
74
  homepage: https://www.github.com/cul/folio_api_client
74
- licenses: []
75
+ licenses:
76
+ - Apache-2.0
75
77
  metadata:
76
78
  homepage_uri: https://www.github.com/cul/folio_api_client
77
79
  source_code_uri: https://www.github.com/cul/folio_api_client