Class: FolioClient

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/folio_client.rb,
lib/folio_client/users.rb,
lib/folio_client/version.rb,
lib/folio_client/inventory.rb,
lib/folio_client/job_status.rb,
lib/folio_client/data_import.rb,
lib/folio_client/authenticator.rb,
lib/folio_client/organizations.rb,
lib/folio_client/records_editor.rb,
lib/folio_client/source_storage.rb,
lib/folio_client/unexpected_response.rb

Overview

Client for interacting with the Folio API rubocop:disable Metrics/ClassLength

Defined Under Namespace

Classes: Authenticator, ConflictError, DataImport, Error, ForbiddenError, Inventory, JobStatus, MultipleResourcesFound, Organizations, RecordsEditor, ResourceNotFound, ServiceUnavailable, SourceStorage, UnauthorizedError, UnexpectedResponse, Users, ValidationError

Constant Summary collapse

DEFAULT_HEADERS =
{
  accept: 'application/json, text/plain',
  content_type: 'application/json'
}.freeze
VERSION =
'0.17.0'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#configObject

Returns the value of attribute config.



89
90
91
# File 'lib/folio_client.rb', line 89

def config
  @config
end

Class Method Details

.configure(url:, login_params:, okapi_headers:, timeout: default_timeout, legacy_auth: true) ⇒ FolioClient

Returns the configured Singleton class.

Parameters:

  • url (String)

    the folio API URL

  • login_params (Hash)

    the folio client login params (username:, password:)

  • okapi_headers (Hash)

    the okapi specific headers to add (X-Okapi-Tenant:, User-Agent:)

  • legacy_auth (Boolean) (defaults to: true)

    true to use legacy /login rather than Poppy /login-with-expiry endpoint

Returns:



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/folio_client.rb', line 55

def configure(url:, login_params:, okapi_headers:, timeout: default_timeout, legacy_auth: true)
  # rubocop:disable Style/OpenStructUse
  instance.config = OpenStruct.new(
    # For the initial token, use a dummy value to avoid hitting any APIs
    # during configuration, allowing `with_token_refresh_when_unauthorized` to handle
    # auto-magic token refreshing. Why not immediately get a valid token? Our apps
    # commonly invoke client `.configure` methods in the initializer in all
    # application environments, even those that are never expected to
    # connect to production APIs, such as local development machines.
    #
    # NOTE: `nil` and blank string cannot be used as dummy values here as
    # they lead to a malformed request to be sent, which triggers an
    # exception not rescued by `with_token_refresh_when_unauthorized`
    token: 'a temporary dummy token to avoid hitting the API before it is needed',
    url: url,
    login_params: ,
    okapi_headers: okapi_headers,
    timeout: timeout,
    legacy_auth: legacy_auth # default true until we have new token endpoint enabled in Poppy
  )
  # rubocop:enable Style/OpenStructUse

  self
end

Instance Method Details

#connectionObject

the base connection to the Folio API



153
154
155
156
157
158
159
160
161
162
# File 'lib/folio_client.rb', line 153

def connection
  @connection ||= Faraday.new(
    url: config.url,
    headers: DEFAULT_HEADERS.merge(config.okapi_headers || {}),
    request: { timeout: config.timeout }
  ) do |faraday|
    faraday.use :cookie_jar, jar: cookie_jar
    faraday.adapter Faraday.default_adapter
  end
end


164
165
166
# File 'lib/folio_client.rb', line 164

def cookie_jar
  @cookie_jar ||= HTTP::CookieJar.new
end

#data_importObject

@ see DataImport#import



213
214
215
216
217
# File 'lib/folio_client.rb', line 213

def data_import(...)
  DataImport
    .new
    .import(...)
end

#default_timeoutObject



268
269
270
# File 'lib/folio_client.rb', line 268

def default_timeout
  120
end

#edit_marc_jsonObject



227
228
229
230
231
# File 'lib/folio_client.rb', line 227

def edit_marc_json(...)
  RecordsEditor
    .new
    .edit_marc_json(...)
end

#fetch_external_idObject



178
179
180
181
182
# File 'lib/folio_client.rb', line 178

def fetch_external_id(...)
  Inventory
    .new
    .fetch_external_id(...)
end

#fetch_hridObject



171
172
173
174
175
# File 'lib/folio_client.rb', line 171

def fetch_hrid(...)
  Inventory
    .new
    .fetch_hrid(...)
end

#fetch_instance_infoObject



185
186
187
188
189
# File 'lib/folio_client.rb', line 185

def fetch_instance_info(...)
  Inventory
    .new
    .fetch_instance_info(...)
end

#fetch_marc_hashObject



192
193
194
195
196
# File 'lib/folio_client.rb', line 192

def fetch_marc_hash(...)
  SourceStorage
    .new
    .fetch_marc_hash(...)
end

#fetch_marc_xmlObject



199
200
201
202
203
# File 'lib/folio_client.rb', line 199

def fetch_marc_xml(...)
  SourceStorage
    .new
    .fetch_marc_xml(...)
end

#force_token_refresh!Object



272
273
274
# File 'lib/folio_client.rb', line 272

def force_token_refresh!
  config.token = Authenticator.token
end

#get(path, params = {}) ⇒ Object

Send an authenticated get request

Parameters:

  • path (String)

    the path to the Folio API request

  • params (Hash) (defaults to: {})

    params to get to the API



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/folio_client.rb', line 94

def get(path, params = {})
  response = with_token_refresh_when_unauthorized do
    connection.get(path, params, { 'x-okapi-token': config.token })
  end

  UnexpectedResponse.call(response) unless response.success?

  return nil if response.body.blank?

  JSON.parse(response.body)
end

#has_instance_status?Boolean

Returns:

  • (Boolean)

See Also:



206
207
208
209
210
# File 'lib/folio_client.rb', line 206

def has_instance_status?(...) # rubocop:disable Naming/PredicateName
  Inventory
    .new
    .has_instance_status?(...)
end

#interface_detailsObject



248
249
250
251
252
# File 'lib/folio_client.rb', line 248

def interface_details(...)
  Organizations
    .new
    .fetch_interface_details(...)
end

#job_profilesObject

@ see DataImport#job_profiles



220
221
222
223
224
# File 'lib/folio_client.rb', line 220

def job_profiles(...)
  DataImport
    .new
    .job_profiles(...)
end

#organization_interfacesObject



241
242
243
244
245
# File 'lib/folio_client.rb', line 241

def organization_interfaces(...)
  Organizations
    .new
    .fetch_interface_list(...)
end

#organizationsObject



234
235
236
237
238
# File 'lib/folio_client.rb', line 234

def organizations(...)
  Organizations
    .new
    .fetch_list(...)
end

#post(path, body = nil, content_type: 'application/json') ⇒ Object

Send an authenticated post request If the body is JSON, it will be automatically serialized rubocop:disable Metrics/MethodLength

Parameters:

  • path (String)

    the path to the Folio API request

  • body (Object) (defaults to: nil)

    body to post to the API as JSON



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/folio_client.rb', line 111

def post(path, body = nil, content_type: 'application/json')
  req_body = content_type == 'application/json' ? body&.to_json : body
  response = with_token_refresh_when_unauthorized do
    req_headers = {
      'x-okapi-token': config.token,
      'content-type': content_type
    }
    connection.post(path, req_body, req_headers)
  end

  UnexpectedResponse.call(response) unless response.success?

  return nil if response.body.blank?

  JSON.parse(response.body)
end

#put(path, body = nil, content_type: 'application/json') ⇒ Object

Send an authenticated put request If the body is JSON, it will be automatically serialized rubocop:disable Metrics/MethodLength

Parameters:

  • path (String)

    the path to the Folio API request

  • body (Object) (defaults to: nil)

    body to put to the API as JSON



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/folio_client.rb', line 134

def put(path, body = nil, content_type: 'application/json')
  req_body = content_type == 'application/json' ? body&.to_json : body
  response = with_token_refresh_when_unauthorized do
    req_headers = {
      'x-okapi-token': config.token,
      'content-type': content_type
    }
    connection.put(path, req_body, req_headers)
  end

  UnexpectedResponse.call(response) unless response.success?

  return nil if response.body.blank?

  JSON.parse(response.body)
end

#user_detailsObject



262
263
264
265
266
# File 'lib/folio_client.rb', line 262

def user_details(...)
  Users
    .new
    .fetch_user_details(...)
end

#usersObject



255
256
257
258
259
# File 'lib/folio_client.rb', line 255

def users(...)
  Users
    .new
    .fetch_list(...)
end