Class: WscSdk::Endpoint

Inherits:
Object
  • Object
show all
Includes:
Loggable
Defined in:
lib/wsc_sdk/endpoint.rb

Overview

A base class for defining endpoint interactions and generating API requests.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Loggable

#logger, #logger=

Constructor Details

#initialize(client, options = {}) ⇒ Endpoint

Instantiate a new endpoint.

Parameters:

  • client (WscSdk::Client)

    The client to associate with the endpoint.

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

    A hash of options

Options Hash (options):

  • :parent_path (String)

    The parent object path to use when generating endpoint requests. This enables chaining models together in the REST pattern.



30
31
32
33
# File 'lib/wsc_sdk/endpoint.rb', line 30

def initialize(client, options={})
  @client       = client
  @parent_path  = options.fetch(:parent_path, nil)
end

Instance Attribute Details

#clientObject (readonly)

Returns the value of attribute client



16
17
18
# File 'lib/wsc_sdk/endpoint.rb', line 16

def client
  @client
end

#parent_pathObject (readonly)

Returns the value of attribute parent_path



16
17
18
# File 'lib/wsc_sdk/endpoint.rb', line 16

def parent_path
  @parent_path
end

Class Method Details

.actions(config = {}) ⇒ Object

Define which built-in actions should be available in the endpoint.

Parameters:

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

    A hash of configuration options

Options Hash (config):

  • :include (Array)

    An array of actions to keep enabled, anything not listed will be disabled.

  • :exclude (Array)

    An array of actions to disable. This option supercedes the :include option.



433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
# File 'lib/wsc_sdk/endpoint.rb', line 433

def self.actions config={}
  available_actions = [:list, :find, :build, :create, :update, :delete]
  disabled_actions  = available_actions.clone

  include_actions   = config.fetch(:include, [])
  include_actions   = [include_actions] unless include_actions.is_a?(Array)
  include_actions   = include_actions.map{ |action| action.to_sym }

  exclude_actions   = config.fetch(:exclude, [])
  exclude_actions   = [exclude_actions] unless include_actions.is_a?(Array)
  exclude_actions   = exclude_actions.map{ |action| action.to_sym }

  # Do the math to determine which actions should be disabled
  disabled_actions  = ((disabled_actions - include_actions) + exclude_actions).flatten.compact

  # Get the intersectino of the available actions and the disabled actions
  # to make sure that we aren't disabling unexpected actions.
  disabled_actions  = available_actions & disabled_actions

  disabled_actions.each do |disabled_action|
    define_method disabled_action.to_sym do |*args|
      raise NoMethodError.new("the '#{disabled_action}' action is not enabled on this endpoint")
    end
  end
end

.model_action(action_name, method, model_class) ⇒ Object

Builds additional action methods for the given model into the endpoint. this allows the endpoint functionality to be extended.

Parameters:

  • action_name (Symbol)

    The name of the action to append to the endpoint path (e.g. /start)

  • method (Symbol)

    The request action method (:get, :post, :put, :patch, :delete)

  • model_class (Class)

    The expected model class that is retuned by the action.



483
484
485
486
487
488
489
490
# File 'lib/wsc_sdk/endpoint.rb', line 483

def self.model_action(action_name, method, model_class)
  define_method action_name.to_sym do |id|
    response    = self.client.send(method.to_sym, [find_path(id), action_name.to_s].join("/"))
    (200..299).include?(response.code) ?
      transform_model(response.body, model_class: model_class) :
      transform_model(response.body, model_class: WscSdk::Models::Error)
  end
end

.model_class(model_class) ⇒ Object

Builds the `model` static method that returns the class of the expected model for the given endpoint.

Parameters:

  • model_class (Class)

    The class of the expected model.



465
466
467
468
469
# File 'lib/wsc_sdk/endpoint.rb', line 465

def self.model_class model_class
  define_singleton_method :model do
    model_class
  end
end

Instance Method Details

#build(attributes = {}) ⇒ WscSdk::Model

Build a new instance of the model class, without committing it to the API.

Parameters:

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

    A hash of attributes to assign to the new instance.

Returns:



107
108
109
# File 'lib/wsc_sdk/endpoint.rb', line 107

def build(attributes={})
  self.class.model.new(self, attributes)
end

#create(model_object) ⇒ WscSdk::Model, Nil

Create a new model using the endpoint.

If successful this method will directly modify the model_object that is provided, and also return a reference to that object.

If the data in the model_object is not valid, then the validation messages will be updated in the errors property, and the method will return a Nil object.

Parameters:

  • model_object (WscSdk::Model)

    The model object to create in the endpoint.

Returns:

  • (WscSdk::Model)

    If the newly created model is valid and returns properly from the endpoint.

  • (Nil)

    If the newly created model is invalid.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/wsc_sdk/endpoint.rb', line 130

def create(model_object)
  return WscSdk::Errors.model_exists(self) unless model_object.new_model?

  payload   = model_object.build_payload
  return WscSdk::Errors.invalid_attributes(self) unless model_object.valid?

  response  = client.post(create_path, body: payload)

  if (200..299).include?(response.code)
    return transform_model(response.body, origin_model: model_object)
  else
    return transform_model(response.body, model_class: WscSdk::Models::Error)
  end
end

#create_pathString

Get the path for creating an individual model

Returns:

  • (String)

    The create path.



262
263
264
# File 'lib/wsc_sdk/endpoint.rb', line 262

def create_path
  list_path
end

#delete(model_object) ⇒ WscSdk::Model, Nil

Delete an existing model in the endpoint.

If the model_object's `WscSdk::Model#new_model?` call returns true, this method becomes an alias for `WscSdk::Model#create(model_object)`

If successful this method will directly modify the model_object that is provided, and also return a reference to that object.

If the data in the model_object is not valid, then the validation messages will be updated in the errors property, and the method will return a Nil object.

Parameters:

  • model_object (WscSdk::Model)

    The model object to create in the endpoint.

Returns:

  • (WscSdk::Model)

    If the newly created model is valid and returns properly from the endpoint.

  • (Nil)

    If the newly created model is invalid.



203
204
205
206
207
208
209
210
211
212
213
# File 'lib/wsc_sdk/endpoint.rb', line 203

def delete(model_object)
  return WscSdk::Errors.model_does_not_exist(self) if model_object.new_model?

  response  = client.delete(delete_path(model_object.primary_key))
  if (200..299).include?(response.code)
    model_object.clear_primary_key
    return model_object
  else
    return transform_model(response.body, model_class: WscSdk::Models::Error)
  end
end

#delete_path(id) ⇒ String

Get the path for deleting an individual model

Parameters:

  • id (Any)

    The unique id of the model.

Returns:

  • (String)

    The destroy path.



286
287
288
# File 'lib/wsc_sdk/endpoint.rb', line 286

def delete_path(id)
  model_path(id)
end

#find(id) ⇒ Object

Find a specific model in the endpoint.

Parameters:

  • id (Any)

    The id/primary key of the model to find.



77
78
79
80
81
82
83
84
# File 'lib/wsc_sdk/endpoint.rb', line 77

def find(id)
  response    = client.get(find_path(id))
  if (200..299).include?(response.code)
    return transform_model(response.body)
  else
    return transform_model(response.body, model_class: WscSdk::Models::Error)
  end
end

#find_path(id) ⇒ String

Get the path for finding an individual model

Parameters:

  • id (Any)

    The unique id of the model.

Returns:

  • (String)

    The find path.



253
254
255
# File 'lib/wsc_sdk/endpoint.rb', line 253

def find_path(id)
  model_path(id)
end

#handle_json_error(json_error, payload = nil) ⇒ Object

If there is an error while attempting to parse inbound JSON, then make sure we have a uniform response mechanism.

A logger error message is written with the error message. A logger debug message is written with the payload information. A WscSdk::Models::Error object is returned

Parameters:

  • json_error (JSON::ParserError)

    The exception raised while parsing the JSON

  • payload (String) (defaults to: nil)

    (nil) If a payload is available, then we will log the details at a DEBUG level.

Raises:

  • (WscSdk::Model::Error)

    Returns an error model so that the SDK can continue without interruption but details will be available, and the `.success?` test will fail.



407
408
409
410
411
# File 'lib/wsc_sdk/endpoint.rb', line 407

def handle_json_error(json_error, payload=nil)
  client.logger.error("Payload Invalid : #{json_error.message}")
  client.logger.debug("Payload Data    : #{payload}") if payload
  return WscSdk::Errors.invalid_payload(self)
end

#list(options = {}) ⇒ Hash<Any,WscSdk::Model>, WscSdk::Models::Error

List all of the models for the endpoint.

Parameters:

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

    A hash of options

Options Hash (options):

  • :pagination (Hash)

    Pagination configuration for the returned list.

  • :filters (Hash)

    Filters to be applied to the list.

Returns:



61
62
63
64
65
66
67
68
69
70
# File 'lib/wsc_sdk/endpoint.rb', line 61

def list(options={})
  url             = list_path
  response        = client.get(url, options)

  if (200..299).include?(response.code)
    return transform_list(response.body)
  else
    return transform_model(response.body, model_class: WscSdk::Models::Error)
  end
end

#list_pathString

Get the path for the list of models

Returns:

  • (String)

    The list path.



229
230
231
# File 'lib/wsc_sdk/endpoint.rb', line 229

def list_path
  [ parent_path, model_name_plural ].compact.join("/")
end

#model_name_pluralString

Get the plural form of the model name.

Returns:

  • (String)

    The plural form of the model name.



304
305
306
307
# File 'lib/wsc_sdk/endpoint.rb', line 304

def model_name_plural
  return nil if self.class.model.nil?
  self.class.model.plural_name
end

#model_name_singularString

Get the singular form of the model name

Returns:

  • (String)

    The singular form of the model name



314
315
316
317
# File 'lib/wsc_sdk/endpoint.rb', line 314

def model_name_singular
  return nil if self.class.model.nil?
  self.class.model.singular_name
end

#model_path(id) ⇒ String

Get the path for an individual model.

Parameters:

  • id (Any)

    The unique id of the model.

Returns:

  • (String)

    The model path.



241
242
243
# File 'lib/wsc_sdk/endpoint.rb', line 241

def model_path(id)
  [ parent_path, model_name_plural, id ].compact.join("/")
end

#refresh(model) ⇒ Object

Refresh the data of a specific model.

Parameters:



90
91
92
93
94
95
96
97
# File 'lib/wsc_sdk/endpoint.rb', line 90

def refresh(model)
  response    = client.get(find_path(model.primary_key))
  if (200..299).include?(response.code)
    return transform_model(response.body, origin_model: model)
  else
    return transform_model(response.body, model_class: WscSdk::Models::Error)
  end
end

#transform_list(payload) ⇒ WscSdk::ModelList

Transform a response payload into a list of models.

Parameters:

  • payload (Hash)

    The response payload from an API request.

Returns:



328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/wsc_sdk/endpoint.rb', line 328

def transform_list(payload)
  list = WscSdk::ModelList.new
  begin
    data    = JSON.parse(payload).deep_symbolize_keys

    data[model_name_plural.to_sym].each do |model_data|
      model = self.class.model.new(self)
      model.ingest_attributes(model_data, write_to_read_only: true, mark_clean: true, partial_data: true)
      list.add(model)
    end

    list.pagination = data[:pagination] if data.has_key?(:pagination)

    return list
  rescue JSON::ParserError => e
    return handle_json_error(e, payload)
  end
end

#transform_model(payload, options = {}) ⇒ WscSdk::Model

Transform a response payload into a model.

Parameters:

  • payload (String)

    The response body from an API request.

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

    A hash of options

Options Hash (options):

  • :model_class (WscSdk::Model)

    The class of the model to transform the payload into. This is set to then endpoints static `Endpoint#model` class that is assigned when the endpoint is built. This option is overridden if the `:origin_model` option is used.

  • :origin_model (WscSdk::Model)

    An existing model that is used instead of generating a new one. This model needs to be the same type of model that is represented by the payload otherwise errors may be generated. This options overrides the `:model_class` options if it's set.

Returns:



370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
# File 'lib/wsc_sdk/endpoint.rb', line 370

def transform_model(payload, options={})
  model_class   = options.fetch(:model_class, self.class.model)
  origin_model  = options.fetch(:origin_model, nil)
  model         = nil

  begin
    data              = JSON.parse(payload).deep_symbolize_keys
    model             = origin_model.nil? ? model_class.new(self) : origin_model
    root_key          = model.class.singular_name.to_sym
    model_data        = data.has_key?(root_key) ? data[root_key] : data

    model.ingest_attributes(model_data, write_to_read_only: true, mark_clean: true)

    return model
  rescue JSON::ParserError => e
    return handle_json_error(e, payload)
  end
end

#update(model_object) ⇒ WscSdk::Model, Nil

Update an existing model in the endpoint.

If the model_object's `WscSdk::Model#new_model?` call returns true, this method becomes an alias for `WscSdk::Model#create(model_object)`

If successful this method will directly modify the model_object that is provided, and also return a reference to that object.

If the data in the model_object is not valid, then the validation messages will be updated in the errors property, and the method will return a Nil object.

Parameters:

  • model_object (WscSdk::Model)

    The model object to create in the endpoint.

Returns:

  • (WscSdk::Model)

    If the newly created model is valid and returns properly from the endpoint.

  • (Nil)

    If the newly created model is invalid.



167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/wsc_sdk/endpoint.rb', line 167

def update(model_object)
  return WscSdk::Errors.model_does_not_exist(self) if model_object.new_model?

  payload   = model_object.build_payload
  return WscSdk::Errors.invalid_attributes(self) unless model_object.valid?

  response  = client.put(update_path(model_object.primary_key), body: payload)
  if (200..299).include?(response.code)
    return transform_model(response.body, origin_model: model_object)
  else
    return transform_model(response.body, model_class: WscSdk::Models::Error)
  end
end

#update_path(id) ⇒ String

Get the path for updating an individual model

Parameters:

  • id (Any)

    The unique id of the model.

Returns:

  • (String)

    The update path.



274
275
276
# File 'lib/wsc_sdk/endpoint.rb', line 274

def update_path(id)
  model_path(id)
end