Class: Usps::Imis::Api

Inherits:
Object
  • Object
show all
Includes:
Requests
Defined in:
lib/usps/imis/api.rb

Overview

The core API wrapper

Constant Summary collapse

NAME =
'USPS iMIS API - Ruby'
AUTHENTICATION_PATH =

Endpoint for (re-)authentication requests

'Token'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(imis_id: nil, record_id: nil) ⇒ Api

A new instance of Api

Parameters:

  • imis_id (Integer, String) (defaults to: nil)

    iMIS ID to select immediately on initialization



62
63
64
65
66
67
# File 'lib/usps/imis/api.rb', line 62

def initialize(imis_id: nil, record_id: nil)
  self.imis_id = imis_id if imis_id
  self.record_id = record_id if record_id
  @logger = Imis.logger('Api')
  Imis.config.validate!
end

Instance Attribute Details

#imis_idObject

Currently selected iMIS ID for API requests



33
34
35
# File 'lib/usps/imis/api.rb', line 33

def imis_id
  @imis_id
end

#lock_imis_idObject (readonly)

Whether to lock changes to the selected iMIS ID



37
38
39
# File 'lib/usps/imis/api.rb', line 37

def lock_imis_id
  @lock_imis_id
end

#loggerObject (readonly)

Tagged logger



41
42
43
# File 'lib/usps/imis/api.rb', line 41

def logger
  @logger
end

#tokenObject (readonly)

API bearer token



23
24
25
# File 'lib/usps/imis/api.rb', line 23

def token
  @token
end

#token_expirationObject (readonly)

Expiration time for the API bearer token

Used to automatically re-authenticate as needed



29
30
31
# File 'lib/usps/imis/api.rb', line 29

def token_expiration
  @token_expiration
end

Class Method Details

.versionObject

Name and version of the API



45
# File 'lib/usps/imis/api.rb', line 45

def self.version = "#{NAME} (v#{Imis::VERSION})"

.with_token(token) ⇒ Object

Create a new instance of Api and provide an existing auth token

Parameters:

  • token (String)

    Auth token



51
52
53
54
55
56
# File 'lib/usps/imis/api.rb', line 51

def self.with_token(token)
  new.tap do |api|
    api.instance_variable_set(:@token, token)
    api.instance_variable_set(:@token_expiration, Time.now + 3600) # Greater than the actual lifetime of the token
  end
end

Instance Method Details

#auth_tokenObject

Used by the CLI wrappers to reduce authentication requests



248
249
250
251
252
# File 'lib/usps/imis/api.rb', line 248

def auth_token
  authenticate

  { token: @token, token_expiration: @token_expiration }
end

#authenticateObject

Authenticate to the iMIS API, and store the access token and expiration time



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/usps/imis/api.rb', line 277

def authenticate
  json = nil # Scope

  logger.tagged('Auth') do
    logger.info 'Authenticating with iMIS'

    request = http_post
    request.body = URI.encode_www_form(
      grant_type: 'password',
      username: Imis.configuration.username,
      password: Imis.configuration.password
    )
    result = submit(request)
    json = JSON.parse(result.body)
  end

  @token = json['access_token']
  @token_expiration = Time.now + json['expires_in'] - 60
end

#business_objectsHash<Symbol, Array<String>>

List of available Business Object names

Returns:

  • (Hash<Symbol, Array<String>>)

    Grouped available Business Objects



233
234
235
236
237
# File 'lib/usps/imis/api.rb', line 233

def business_objects
  abc, other = query('BOEntityDefinition').map(&:entity).partition { it.include?('ABC') }

  { abc:, other: }
end

#fetch(field_key) ⇒ Object Also known as: []

Convenience alias for reading mapped fields

Returns:

  • Value of the specified field



207
# File 'lib/usps/imis/api.rb', line 207

def fetch(field_key) = mapper.fetch(field_key)

#fetch_all(*fields) ⇒ Array

Convenience alias for reading multiple mapped fields

Returns:

  • (Array)

    Values of the specified fields



214
# File 'lib/usps/imis/api.rb', line 214

def fetch_all(*fields) = mapper.fetch_all(*fields)

#http_connectionObject

Persistent HTTP connection for reuse across requests



256
257
258
259
260
261
262
263
264
265
266
267
268
269
# File 'lib/usps/imis/api.rb', line 256

def http_connection
  return @http_connection if @http_connection&.started?

  hostname = URI(Imis.configuration.hostname)
  @http_connection = Net::HTTP.new(hostname.host, hostname.port).tap do |http|
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_PEER
    http.open_timeout = 10
    http.read_timeout = 30
    http.write_timeout = 30
    http.keep_alive_timeout = 30
    http.start
  end
end

#imis_id_for(certificate) ⇒ Integer

Convert a member’s certificate number into an iMIS ID number

Parameters:

  • certificate (String)

    Certificate number to lookup the corresponding iMIS ID for

Returns:

  • (Integer)

    Corresponding iMIS ID



117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/usps/imis/api.rb', line 117

def imis_id_for(certificate)
  raise Errors::LockedIdError if lock_imis_id

  logger.debug "Fetching iMIS ID for #{certificate}"

  result = query(Imis.configuration.imis_id_query_name, { certificate: })
  page = result.page.tap { logger.tagged('Response').debug it }
  raise Errors::NotFoundError, 'Member not found' if page.empty?

  self.imis_id = page.first['ID'].to_i
rescue Errors::ResponseError
  raise Errors::NotFoundError, 'Member not found'
end

#instance_variables_to_inspectObject

Ruby 3.5 instance variable filter



273
# File 'lib/usps/imis/api.rb', line 273

def instance_variables_to_inspect = %i[@token_expiration @imis_id]

#mapperObject

An instance of Mapper, using this instance as its parent Api



199
200
201
# File 'lib/usps/imis/api.rb', line 199

def mapper
  @mapper ||= Mapper.new(self)
end

#on(business_object_name, ordinal: nil) ⇒ Usps::Imis::BusinessObject

Run requests as DSL, with specific BusinessObject only maintained for this scope

If no block is given, this returns the specified BusinessObject.

Parameters:

  • business_object_name (String, Symbol)

    Name of the business object

  • ordinal (Integer) (defaults to: nil)

    Ordinal to build override ID param of the URL (e.g. used for Panels)

Returns:



190
191
192
193
194
195
# File 'lib/usps/imis/api.rb', line 190

def on(business_object_name, ordinal: nil, &)
  object = BusinessObject.new(self, business_object_name, ordinal:)
  return object unless block_given?

  object.instance_eval(&)
end

#panelsObject

Convenience accessor for available Panel objects, each using this instance as its parent Api



242
243
244
# File 'lib/usps/imis/api.rb', line 242

def panels
  @panels ||= Panels.all(self)
end

#put_field(field_key, value) ⇒ Array Also known as: []=

Convenience alias for updating mapped fields

Returns:

  • (Array)

    Array containing the updated object



220
# File 'lib/usps/imis/api.rb', line 220

def put_field(field_key, value) = update(field_key => value)

#query(query_name, query_params = {}) ⇒ Usps::Imis::Query

Build a Query interface

Works with IQA queries and Business Objects

Parameters:

  • query_name (String)

    Full path of the query, e.g. $/_ABC/Fiander/iMIS_ID

Returns:



179
# File 'lib/usps/imis/api.rb', line 179

def query(query_name, query_params = {}) = Query.new(self, query_name, **query_params)

#record_idObject

Currently selected Record ID for API requests

Defaults to the iMIS ID



109
# File 'lib/usps/imis/api.rb', line 109

def record_id = @record_id || imis_id

#record_id=(id) ⇒ Integer

Manually set the current record ID

Parameters:

  • id (Integer, String)

    Record ID to select for future requests

Returns:

  • (Integer)

    Record ID

Raises:



97
98
99
100
101
102
103
# File 'lib/usps/imis/api.rb', line 97

def record_id=(id)
  return if id.nil?

  raise Errors::LockedIdError if lock_imis_id

  @record_id = id.to_i
end

#update(data) ⇒ Usps::Imis::Data

Convenience alias for updating mapped fields

Returns:



227
# File 'lib/usps/imis/api.rb', line 227

def update(data) = mapper.update(data)

#with(id = nil, certificate: nil, record_id: nil) ⇒ Usps::Imis::Api

Run requests as DSL, with specific iMIS ID only maintained for this scope

Either id or certificate is required.

While in this block, changes to the value of imis_id are not allowed

If no block is given, this sets the iMIS ID and returns self.

Examples:

with(12345) do
  update(mm: 15)
end

Parameters:

  • id (Integer, String) (defaults to: nil)

    iMIS ID to select for requests within the block

  • certificate (String) (defaults to: nil)

    Certificate number to convert to iMIS ID and select for requests within the block

  • record_id (Integer) (defaults to: nil)

    Record ID to select for requests within the block

Returns:



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/usps/imis/api.rb', line 150

def with(id = nil, certificate: nil, record_id: nil, &)
  raise ArgumentError, 'Must provide id or certificate' unless id || certificate

  old_id = imis_id
  old_record_id = @record_id

  id.nil? ? imis_id_for(certificate) : self.imis_id = id
  self.record_id = record_id
  return self unless block_given?

  @lock_imis_id = true
  instance_eval(&)
ensure
  if block_given?
    @lock_imis_id = false
    self.imis_id = old_id
    self.record_id = old_record_id
  end
end