Class: OCI::ApiClient

Inherits:
Object
  • Object
show all
Defined in:
lib/oci/api_client.rb

Overview

The base API client which contains functionality make requests and receive responses from OCI services. This client also handles request serialization and response deserialization

Constant Summary collapse

OCI_SDK_APPEND_USER_AGENT =
'OCI_SDK_APPEND_USER_AGENT'.freeze
VALID_COLLECTION_FORMATS =

Maps collection format types (as per the collectionFormat types described here: swagger.io/docs/specification/2-0/describing-parameters/) to the delimiters we should use to separate values.

The :multi type contains no delimiter because this means we should preserve values as a collection rather than transforming them into a single string

{
  multi: nil,
  csv: ','.freeze,
  ssv: ' '.freeze,
  pipes: '|'.freeze,

  # this is double quoted so it is interpreted as a tab rather than as a literal slash ('\') followed by a 't'
  tsv: "\t".freeze
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, signer, proxy_settings: nil) ⇒ ApiClient

Returns a new instance of ApiClient.



94
95
96
97
98
99
100
101
102
103
# File 'lib/oci/api_client.rb', line 94

def initialize(config, signer, proxy_settings: nil)
  raise "Missing the required parameter 'config' when initializing ApiClient." if config.nil?
  raise "Missing the required parameter 'signer' when initializing ApiClient." if signer.nil?

  @config = config
  @signer = signer
  @default_headers = {}
  @request_option_overrides = {}
  @proxy_settings = proxy_settings
end

Instance Attribute Details

#configObject

The Config object holding settings to be used in the API client.



74
75
76
# File 'lib/oci/api_client.rb', line 74

def config
  @config
end

#default_headersHash

Defines the headers to be used in HTTP requests of all API calls by default.

Returns:

  • (Hash)


79
80
81
# File 'lib/oci/api_client.rb', line 79

def default_headers
  @default_headers
end

#proxy_settingsOCI::ApiClientProxySettings

The proxy settings which this ApiClient will use



92
93
94
# File 'lib/oci/api_client.rb', line 92

def proxy_settings
  @proxy_settings
end

#request_option_overridesHash

Request options to be sent with Net::HTTP. These options will override any defaults normally set by ApiClient. See http://ruby-doc.org/stdlib-2.4.1/libdoc/net/http/rdoc/Net/HTTP.html#method-c-start for some of the available options.

Returns:

  • (Hash)


87
88
89
# File 'lib/oci/api_client.rb', line 87

def request_option_overrides
  @request_option_overrides
end

Class Method Details

.append_query_params(url, query_params) ⇒ Object



192
193
194
195
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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/oci/api_client.rb', line 192

def self.append_query_params(url, query_params)
  return url if query_params.empty?

  # First divide our query params into ones where the param value is a simple value (e.g. a string), an array or a hash.
  # The params  where the value is a hash are, for example, tags we need to handle differently for inclusion in the query
  # string. We also need to handle array params differently in the query string since the values should appear as separate entries
  # in the query string with the same key (this corresponds to using collectionFormat=multi in Swagger)
  #
  # An example query_params is:
  #
  #   {
  #       "stuff" => "things",
  #       "anArrayType" => ["hello", "world"]
  #       "hashType" => { "key" => ["val1", "val2", "val3"], "key2" => ["val1"] },
  #
  #   }
  #
  # So our simple_params will be: { "stuff" => "things" }
  # And our array_params will be: { "anArrayType" => ["hello", "world"]}
  # And our hash_params will be: { "hashType" => { "key" => ["val1", "val2", "val3"], "key2" => ["val1"] }
  simple_params = query_params.select { |_k, v| !v.is_a?(Hash) && !v.is_a?(Array) }.to_h
  array_params = query_params.select { |_k, v| v.is_a?(Array) }.to_h
  hash_params = query_params.select { |_k, v| v.is_a?(Hash) }.to_h

  # Simple params just go key to value
  base_query_string = ''

  base_query_string << simple_params.map { |k, v| "#{k}=#{cgi_escape_query_param(v)}" }.join('&') unless simple_params.empty?

  # Using the previous comment:
  #   k = "anArrayType", v = ["hello", "world"]
  #
  # And we want query string params like #{k}=#{v[0]}&#{k}=#{v[1]}&#{k}=#{v[2]}...
  # So the same key is repeated, but each value is a different value from the array
  array_params.each do |k, v|
    v.each do |query_string_val|
      base_query_string << '&' unless base_query_string.empty?
      base_query_string << "#{k}=#{cgi_escape_query_param(query_string_val)}"
    end
  end

  # Using the previous comment:
  #    k = "hashType", v = { "key1" => [...] }
  #
  # Hash params are exploded as follows:
  #
  #    - If value in v is an array then we explode the content like: #{k}.#{v.key}=#{v.value[0]}&#{k}.#{v.key}=#{v.value[1]}&... so that there is
  #      one query string parameter per item in the array
  #    - If value in v is not an array then we explode the content like: #{k}.#{v.key}=#{v.value}
  hash_params.each do |k, v|
    v.each do |tag_key, tag_val|
      # TODO: Should this be ERB::Util.url_encode instead? CGI.escape gives "+" here but url_encode will give %20
      # CGI.escape is what we've been using until now, and it looks like it works...A literal "+" in the string will
      # be encoded to %2B
      query_string_val = if tag_val.is_a?(Array)
                           # to_s tag_key to avoid errors around implicit conversion of symbols to strings
                           tag_val.map do |tv|
                             "#{k}.#{cgi_escape_query_param(tag_key)}=#{cgi_escape_query_param(tv)}"
                           end.join('&')
                         else
                           "#{k}.#{cgi_escape_query_param(tag_key)}=#{cgi_escape_query_param(tag_val)}"
                         end
      base_query_string << '&' unless base_query_string.empty?
      base_query_string << query_string_val
    end
  end

  url << '?' unless base_query_string.empty?
  url << base_query_string

  url
end

.build_collection_params(collection, collection_format) ⇒ Object

rubocop:enable Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity, Layout/EmptyLines



179
180
181
182
183
184
185
186
187
# File 'lib/oci/api_client.rb', line 179

def self.build_collection_params(collection, collection_format)
  if collection_format.nil? || !VALID_COLLECTION_FORMATS.key?(collection_format.to_sym)
    raise "Invalid collection_format: #{collection_format}. Must be one of: #{VALID_COLLECTION_FORMATS.keys}"
  end

  return collection if collection_format == :multi

  collection.join(VALID_COLLECTION_FORMATS[collection_format.to_sym])
end

.build_request_idObject

Builds the client info string to be sent with each request.



24
25
26
# File 'lib/oci/api_client.rb', line 24

def build_request_id
  SecureRandom.uuid.delete!('-').upcase
end

.build_user_agentObject

Build the user agent string to be sent with each request.



34
35
36
37
# File 'lib/oci/api_client.rb', line 34

def build_user_agent
  "#{}#{OCI.sdk_name} (ruby #{RUBY_VERSION}; #{RUBY_PLATFORM})" unless ENV[OCI_SDK_APPEND_USER_AGENT]
  "#{}#{OCI.sdk_name} (ruby #{RUBY_VERSION}; #{RUBY_PLATFORM}) #{ENV[OCI_SDK_APPEND_USER_AGENT]}"
end

.build_user_infoObject

Builds the client info string to be sent with each request.



29
30
31
# File 'lib/oci/api_client.rb', line 29

def 
  "Oracle-RubySDK/#{VERSION}"
end

Instance Method Details

#build_user_agentObject

Build the user agent string that also includes the additional_user_agent to be sent with each request.



267
268
269
270
# File 'lib/oci/api_client.rb', line 267

def build_user_agent
  agent = self.class.build_user_agent
  !config.nil? && !config.additional_user_agent.nil? ? "#{agent} #{config.additional_user_agent}" : agent
end

#call_api(http_method, path, endpoint, opts, &block) ⇒ Array<(Object, Fixnum, Hash)>

Call an API with given options.

Parameters:

  • http_method (Symbol)

    HTTP method/verb (e.g. :post, :get)

  • path (String)

    URL path (e.g. /volumeAttachments/)

  • endpoint (String)

    URL of the endpoint (e.g iaas.us-phoenix-1.oraclecloud.com/20160918)

  • opts (Hash)

    a customizable set of options

  • [Block] (Hash)

    a customizable set of options

Options Hash (opts):

  • :header_params (Hash)

    Header parameters

  • :query_params (Hash)

    Query parameters

  • :form_params (Hash)

    Form parameters

  • :operation_signing_strategy (String)

    The signing strategy for the api operation

  • :body (Object)

    HTTP body in JSON

Returns:

  • (Array<(Object, Fixnum, Hash)>)

    an array of 3 elements: the data deserialized from response body (could be nil), response status code, and response headers.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/oci/api_client.rb', line 123

def call_api(http_method, path, endpoint, opts, &block)
  http_method = http_method.to_sym.downcase

  if http_method != :get
    return call_api_inner(http_method, path, endpoint, opts, &block) unless using_refresh_eligible_signer?

    return instance_principals_signer_wrapped_call do
      call_api_inner(http_method, path, endpoint, opts, &block)
    end
  end

  # Wrap get calls in a lambda that can be called later for paging
  # and wait_until.
  proc = lambda { |page|
    unless page.nil?
      opts[:query_params] ||= {}
      opts[:query_params][:page] = page
      opts[:query_params][:start] = page if opts[:return_type] == 'OCI::ObjectStorage::Models::ListObjects'
    end

    return call_api_inner(http_method, path, endpoint, opts, &block)
  }

  response = proc.call(nil) unless using_refresh_eligible_signer?
  response = instance_principals_signer_wrapped_call { proc.call(nil) } if using_refresh_eligible_signer?

  response.api_call = proc
  response
end

#object_to_http_body(model) ⇒ String

Convert object (array, hash, object, etc) to JSON string.

Parameters:

  • model (Object)

    object to be converted into JSON string

Returns:

  • (String)

    JSON string representation of the object



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/oci/api_client.rb', line 156

def object_to_http_body(model)
  # to support IO-like object as well like StringIO
  return model if model.nil? || model.is_a?(String) || (model.respond_to?(:read) && model.respond_to?(:write))

  # Supports IO-wrapping objects we can convert to an IO. An example is Rails'
  # ActionDispatch::Http::UploadedFile, which wraps an IO (a Tempfile) but
  # doesn't expose all the IO operations directly (e.g. you can't write to it, it's not seekable)
  #
  # This should be safe to use with IO and its subclasses as well as to_io is a method on IO:
  # http://ruby-doc.org/core-2.3.1/IO.html#method-i-to_io and returns itself if called on
  # an IO
  return model.to_io if (model.respond_to?(:read) || model.respond_to?(:write)) && model.respond_to?(:to_io)

  local_body = if model.is_a?(Array)
                 model.map { |m| object_to_hash(m) }
               else
                 object_to_hash(model)
               end

  local_body.to_json
end