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



252
253
254
255
256
# File 'lib/usps/imis/api.rb', line 252

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



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/usps/imis/api.rb', line 281

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



237
238
239
240
241
# File 'lib/usps/imis/api.rb', line 237

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

  { abc:, other: }
end

#fetchObject Also known as: []

Convenience alias for reading mapped fields

Returns:

  • Value of the specified field



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

delegate :fetch, to: :mapper

#fetch_allArray

Convenience alias for reading multiple mapped fields

Returns:

  • (Array)

    Values of the specified fields



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

delegate :fetch_all, to: :mapper

#http_connectionObject

Persistent HTTP connection for reuse across requests



260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/usps/imis/api.rb', line 260

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



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

def instance_variables_to_inspect = %i[@token_expiration @imis_id]

#mapperObject

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



203
204
205
# File 'lib/usps/imis/api.rb', line 203

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)

Yields:

  • Block context to run requests on a specific BusinessObject

Yield Parameters:

Returns:



194
195
196
197
198
199
# File 'lib/usps/imis/api.rb', line 194

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



246
247
248
# File 'lib/usps/imis/api.rb', line 246

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



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

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:



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

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

#updateUsps::Imis::Data

Convenience alias for updating mapped fields

Returns:



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

delegate :update, to: :mapper

#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

Yields:

  • Block context to run requests with a specific iMIS ID

Yield Parameters:

Returns:



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

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