class Aspire::API::JSON

A wrapper class for the Aspire JSON API

Constants

API_ROOT

The default API root URL

API_ROOT_AUTH

The default authentication API root URL

Attributes

api_root[RW]

@!attribute [rw] api_root

@return [String] the base URL of the Aspire JSON APIs
api_root_auth[RW]

@!attribute [rw] api_root_auth

@return [String] the base URL of the Aspire Persona authentication API
api_version[RW]

@!attribute [rw] api_version

@return [Integer] the version of the Aspire JSON APIs
rate_limit[RW]

@!attribute [rw] rate_limit

@return [Integer] the rate limit value from the most recent API call
rate_remaining[RW]

@!attribute [rw] rate_remaining

@return [Integer] the rate remaining value from the most recent API
  call (the number of calls remaining within the current limit period)
rate_reset[RW]

@!attribute [rw] rate_reset

@return [Integer] the rate reset value from the most recent API call
  (the time in seconds since the Epoch until the next limit period)

Public Class Methods

new(api_client_id = nil, api_secret = nil, tenancy_code = nil, **opts) click to toggle source

Initialises a new API instance @param api_client_id [String] the API client ID @param api_secret [String] the API secret associated with the client ID @param tenancy_code [String] the Aspire short tenancy code @param opts [Hash] API customisation options @option opts [String] :api_root the base URL of the Aspire JSON APIs @option opts [String] :api_root_auth the base URL of the Aspire Persona

authentication API

@option opts [Integer] :api_version the version of the Aspire JSON APIs @option opts [Logger] :logger a logger for activity logging @option opts [Integer] :timeout the API call timeout period in seconds @return [void]

Calls superclass method Aspire::API::Base::new
# File lib/aspire/api/json.rb, line 53
def initialize(api_client_id = nil, api_secret = nil, tenancy_code = nil,
               **opts)
  super(tenancy_code, **opts)
  @api_client_id = api_client_id
  @api_secret = api_secret
  @api_token = nil
  self.api_root = opts[:api_root] || API_ROOT
  self.api_root_auth = opts[:api_root_auth] || API_ROOT_AUTH
  self.api_version = opts[:api_version] || 2
  rate_limit
end

Public Instance Methods

api_url(path) click to toggle source

Returns a full Aspire JSON API URL. Full URLs are returned as-is, partial endpoint paths are expanded with the API root, version and tenancy code. @param path [String] the full URL or partial endpoint path @return [String] the full JSON API URL

# File lib/aspire/api/json.rb, line 70
def api_url(path)
  return path if path.include?('//')
  "#{api_root}/#{api_version}/#{tenancy_code}/#{path}"
end
call(path, headers: nil, options: nil, payload: nil, **params) { |response, data| ... } click to toggle source

Calls an Aspire JSON API method and returns the parsed JSON response Additional keyword parameters are passed as query string parameters to the API call. @param path [String] the path of the API call @param headers [Hash<String, String>] HTTP headers for the API call @param options [Hash<String, Object>] options for the REST client @param payload [String, nil] the data to post to the API call @return [Hash] the parsed JSON content from the API response @yield [response, data] Passes the REST client response and parsed JSON

hash to the block

@yieldparam [RestClient::Response] the REST client response @yieldparam [Hash] the parsed JSON data from the response

# File lib/aspire/api/json.rb, line 87
def call(path, headers: nil, options: nil, payload: nil, **params)
  rest_options = call_rest_options(path,
                                   headers: headers, options: options,
                                   payload: payload, params: params)
  response, data = call_api_with_auth(**rest_options)
  yield(response, data) if block_given?
  data
end

Private Instance Methods

api_token(refresh = false) click to toggle source

Returns an Aspire OAuth API token. New tokens are retrieved from the

Aspire Persona API and cached for subsequent API calls.

@param refresh [Boolean] if true, force retrieval of a new token @return [String] the API token

# File lib/aspire/api/json.rb, line 102
def api_token(refresh = false)
  # Return the cached token unless forcing a refresh
  return @api_token unless @api_token.nil? || refresh
  # Set the token to nil to indicate that there is no current valid token
  # in case an exception is thrown by the API call.
  @api_token = nil
  # Get and return the API token
  _response, data = call_api(**api_token_rest_options)
  @api_token = data['access_token']
end
api_token_authorization() click to toggle source

Returns the HTTP Basic authentication token @return [String] the Basic authentication token

# File lib/aspire/api/json.rb, line 115
def api_token_authorization
  Base64.strict_encode64("#{@api_client_id}:#{@api_secret}")
end
api_token_rest_headers() click to toggle source

Returns the HTTP headers for the token retrieval API call

# File lib/aspire/api/json.rb, line 120
def api_token_rest_headers
  {
    Authorization: "basic #{api_token_authorization}",
    'Content-Type'.to_sym => 'application/x-www-form-urlencoded'
  }
end
api_token_rest_options() click to toggle source
# File lib/aspire/api/json.rb, line 127
def api_token_rest_options
  rest_options = {
    headers: api_token_rest_headers,
    payload: { grant_type: 'client_credentials' },
    url: api_root_auth
  }
  common_rest_options(rest_options)
  rest_options[:method] = :post
  rest_options
end
auth_failed(response) click to toggle source

Returns true if the HTTP response is an authentication failure @param response [RestClient::Response] the REST client response @return [Boolean] true on authentication failure, false otherwise

# File lib/aspire/api/json.rb, line 141
def auth_failed(response)
  response && response.code == 401
end
call_api_response(response) click to toggle source

Performs custom HTTP response processing @param response [RestClient::Response] the REST client response @return [void]

# File lib/aspire/api/json.rb, line 148
def call_api_response(response)
  rate_limit(headers: response.headers)
end
call_api_with_auth(**rest_options) click to toggle source

Calls an authenticated Aspire API endpoint and processes the response. The call is made first with the currently-cached authentication token. If this fails due to authentication, the token is refreshed and the call is repeated once with the new token. @see (call_api)

# File lib/aspire/api/json.rb, line 157
def call_api_with_auth(**rest_options)
  refresh = false
  loop do
    token = api_token(refresh)
    rest_options[:headers]['Authorization'] = "Bearer #{token}"
    response, data = call_api(**rest_options)
    # Stop if we have a valid response or we've already tried to refresh
    #   the token.
    return response, data unless auth_failed(response) && !refresh
    # The API token may have expired, try one more time with a new token
    refresh = true
  end
end
rate_limit_header(header, headers, default) click to toggle source

Returns the numeric value of a rate-limit header @param header [String, Symbol] the header (minus x_ratelimit_ prefix) @param headers [Hash] the HTTP response headers @param default [Integer, nil] the default value if the header is missing @return [Integer, nil] the numeric value of the header

# File lib/aspire/api/json.rb, line 189
def rate_limit_header(header, headers, default)
  value = headers["x_ratelimit_#{header}".to_sym]
  value ? value.to_i : default
end