Module: Scorpio::OpenAPI::Operation

Includes:
Configurables
Included in:
V2::Operation, V3::Operation
Defined in:
lib/scorpio/openapi/operation.rb

Overview

An OpenAPI operation

Scorpio::OpenAPI::Operation is a module common to V2 and V3 operations.

Defined Under Namespace

Modules: Configurables

Instance Attribute Summary

Attributes included from Configurables

#base_url, #faraday_adapter, #faraday_builder, #logger, #request_headers, #user_agent

Instance Method Summary collapse

Instance Method Details

#build_request(configuration = {}, &b) ⇒ Scorpio::Request

instantiates a Request for this operation. parameters are all passed to Request#initialize.

Returns:



168
169
170
171
# File 'lib/scorpio/openapi/operation.rb', line 168

def build_request(configuration = {}, &b)
  @request_class ||= Scorpio::Request.request_class_by_operation(self)
  @request_class.new(configuration, &b)
end

Runs this operation with the given request config, and yields the resulting Ur. If the response contains a Link header with a next link (and that link's URL corresponds to this operation), this operation is run again to that link's URL, that request's Ur yielded, and a next link in that response is followed. This repeats until a response does not contain a Link header with a next link.

Parameters:

  • configuration (#to_hash) (defaults to: {})

    a hash keyed with configurable attributes for the request - instance methods of Scorpio::Request::Configurables, whose values will be assigned for those attributes.

Yields:

Returns:

  • (Enumerator, nil)


196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/scorpio/openapi/operation.rb', line 196

def each_link_page(configuration = {}, &block)
  init_request = build_request(configuration)
  next_page = proc do |last_page_ur|
    nextlinks = last_page_ur.response.links.select { |link| link.rel?('next') }
    if nextlinks.size == 0
      # no next link; we are at the end
      nil
    elsif nextlinks.size == 1
      nextlink = nextlinks.first
      # we do not use Addressable::URI#join as the paths should just be concatenated, not resolved.
      # we use File.join just to deal with consecutive slashes.
      template = Addressable::Template.new(File.join(init_request.base_url, path_template_str))
      target_uri = nextlink.absolute_target_uri
      path_params = template.extract(target_uri.merge(query: nil))
      unless path_params
        raise("the URI of the link to the next page did not match the URI of this operation")
      end
      query_params = target_uri.query_values
      run_ur(
        path_params: path_params,
        query_params: query_params,
      )
    else
      # TODO better error class / context / message
      raise("response included multiple links with rel=next")
    end
  end
  init_request.each_page_ur(next_page: next_page, &block)
end

#http_methodString

the HTTP method of this operation as indicated by the attribute name for this operation from the parent PathItem

Returns:

  • (String)

Raises:



96
97
98
99
100
# File 'lib/scorpio/openapi/operation.rb', line 96

def http_method
  return @http_method if instance_variable_defined?(:@http_method)
  raise(Bug) unless jsi_parent_node.is_a?(Scorpio::OpenAPI::V2::PathItem) || jsi_parent_node.is_a?(Scorpio::OpenAPI::V3::PathItem)
  @http_method = jsi_ptr.tokens.last
end

#human_idString

a short identifier for this operation appropriate for an error message

Returns:

  • (String)


104
105
106
# File 'lib/scorpio/openapi/operation.rb', line 104

def human_id
  operationId || "path: #{path_template_str}, method: #{http_method}"
end

#inferred_parameters#to_ary<#to_h>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

the parameters specified for this operation, plus any others scorpio considers to be parameters.

this method is not intended to be API-stable at the moment.

Returns:

  • (#to_ary<#to_h>)


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/scorpio/openapi/operation.rb', line 125

def inferred_parameters
  parameters = self.parameters ? self.parameters.to_a.dup : []
  path_template.variables.each do |var|
    unless parameters.any? { |p| p['in'] == 'path' && p['name'] == var }
      # we could instantiate this as a V2::Parameter or a V3::Parameter
      # or a ParameterWithContentInPath or whatever. but I can't be bothered.
      parameters << {
        'name' => var,
        'in' => 'path',
        'required' => true,
        'type' => 'string',
      }
    end
  end
  parameters
end

#oa_response(status:) ⇒ Scorpio::OpenAPI::V3::Response, Scorpio::OpenAPI::V2::Response

Parameters:

  • status (String, Integer)

Returns:



110
111
112
113
114
115
116
117
# File 'lib/scorpio/openapi/operation.rb', line 110

def oa_response(status: )
  status = status.to_s if status.is_a?(Numeric)
  if responses
    _, oa_response = responses.detect { |k, v| k.to_s == status }
    oa_response ||= responses['default']
  end
  oa_response
end

#openapi_documentScorpio::OpenAPI::Document

the document whence this operation came



62
63
64
# File 'lib/scorpio/openapi/operation.rb', line 62

def openapi_document
  jsi_parent_nodes.detect { |p| p.is_a?(Scorpio::OpenAPI::Document) }
end

#path_templateAddressable::Template

the path as an Addressable::Template

Returns:

  • (Addressable::Template)


76
77
78
79
# File 'lib/scorpio/openapi/operation.rb', line 76

def path_template
  return @path_template if instance_variable_defined?(:@path_template)
  @path_template = Addressable::Template.new(path_template_str)
end

#path_template_strString

Returns:

  • (String)

Raises:



67
68
69
70
71
72
# File 'lib/scorpio/openapi/operation.rb', line 67

def path_template_str
  return @path_template_str if instance_variable_defined?(:@path_template_str)
  raise(Bug) unless jsi_parent_node.is_a?(Scorpio::OpenAPI::V2::PathItem) || jsi_parent_node.is_a?(Scorpio::OpenAPI::V3::PathItem)
  raise(Bug) unless jsi_parent_node.jsi_parent_node.is_a?(Scorpio::OpenAPI::V2::Paths) || jsi_parent_node.jsi_parent_node.is_a?(Scorpio::OpenAPI::V3::Paths)
  @path_template_str = jsi_parent_node.jsi_ptr.tokens.last
end

#request_accessor_moduleModule

a module with accessor methods for unambiguously named parameters of this operation.

Returns:

  • (Module)


144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/scorpio/openapi/operation.rb', line 144

def request_accessor_module
  return @request_accessor_module if instance_variable_defined?(:@request_accessor_module)
  @request_accessor_module = begin
    params_by_name = inferred_parameters.group_by { |p| p['name'] }
    Module.new do
      instance_method_modules = [Request, Request::Configurables]
      instance_method_names = instance_method_modules.map do |mod|
        (mod.instance_methods + mod.private_instance_methods).map(&:to_s)
      end.inject(Set.new, &:merge)
      params_by_name.each do |name, params|
        next if instance_method_names.include?(name)
        if params.size == 1
          param = params.first
          define_method("#{name}=") { |value| set_param_from(param['in'], param['name'], value) }
          define_method(name) { get_param_from(param['in'], param['name']) }
        end
      end
    end
  end
end

#run(configuration = {}, &b) ⇒ Object

runs a Request for this operation - see Request#run. parameters are all passed to Request#initialize.

Returns:

  • response body object



183
184
185
# File 'lib/scorpio/openapi/operation.rb', line 183

def run(configuration = {}, &b)
  build_request(configuration, &b).run
end

#run_ur(configuration = {}, &b) ⇒ Scorpio::Ur

runs a Request for this operation, returning a Ur. parameters are all passed to Request#initialize.

Returns:



176
177
178
# File 'lib/scorpio/openapi/operation.rb', line 176

def run_ur(configuration = {}, &b)
  build_request(configuration, &b).run_ur
end

#uri_template(base_url: self.base_url) ⇒ Addressable::Template

the URI template, consisting of the base_url concatenated with the path template

Parameters:

  • base_url (#to_str) (defaults to: self.base_url)

    the base URL to which the path template is appended

Returns:

  • (Addressable::Template)


84
85
86
87
88
89
90
91
# File 'lib/scorpio/openapi/operation.rb', line 84

def uri_template(base_url: self.base_url)
  unless base_url
    raise(ArgumentError, "no base_url has been specified for operation #{self}")
  end
  # we do not use Addressable::URI#join as the paths should just be concatenated, not resolved.
  # we use File.join just to deal with consecutive slashes.
  Addressable::Template.new(File.join(base_url, path_template_str))
end

#v2?Boolean

openapi v2?

Returns:

  • (Boolean)


56
57
58
# File 'lib/scorpio/openapi/operation.rb', line 56

def v2?
  is_a?(V2::Operation)
end

#v3?Boolean

openapi v3?

Returns:

  • (Boolean)


50
51
52
# File 'lib/scorpio/openapi/operation.rb', line 50

def v3?
  is_a?(V3::Operation)
end