Class: Miasma::Types::Api
- Inherits:
-
Object
- Object
- Miasma::Types::Api
- Includes:
- Utils::Lazy, Utils::Memoization
- Defined in:
- lib/miasma/types/api.rb
Overview
Remote API connection
Direct Known Subclasses
Models::AutoScale, Models::Compute, Models::LoadBalancer, Models::Orchestration, Models::Storage
Constant Summary collapse
- VALID_REQUEST_RETRY_METHODS =
HTTP request methods that are allowed retry
[:get, :head]
- MAX_REQUEST_RETRIES =
Maximum allowed HTTP request retries (for non-HTTP related errors)
5
Instance Method Summary collapse
-
#after_setup(creds) ⇒ TrueClass
Simple hook for concrete APIs to make adjustments after attribute population and prior to connection.
-
#api_for(type) ⇒ Api
Build new API for specified type using current provider / creds.
-
#connect ⇒ self
Connect to the remote API.
- #connection ⇒ HTTP
-
#custom_setup(creds) ⇒ TrueClass
Simple hook for concrete APIs to make adjustments prior to initialization and connection.
-
#endpoint ⇒ String
Url endpoint.
-
#format_response(result, extract_body = true) ⇒ Smash
Makes best attempt at formatting response.
-
#from_json(string) ⇒ Hash, ...
Convert from JSON.
-
#from_xml(string) ⇒ Hash, ...
Convert from JSON.
-
#initialize(creds) ⇒ self
constructor
Create new API connection.
-
#make_request(connection, http_method, request_args) ⇒ HTTP::Response
Perform request.
-
#perform_request_retry(exception) ⇒ TrueClass, FalseClass
Determine if a retry on the request should be performed.
-
#provider ⇒ Symbol
Name of provider.
-
#request(args) ⇒ Smash
Perform request to remote API.
-
#retryable_allowed?(http_method) ⇒ TrueClass, FalseClass
Determine if request type is allowed to be retried.
-
#retryable_request(http_method) { ... } ⇒ Object
If HTTP request method is allowed to be retried then retry request on non-response failures.
Constructor Details
#initialize(creds) ⇒ self
Create new API connection
21 22 23 24 25 26 27 28 29 30 |
# File 'lib/miasma/types/api.rb', line 21 def initialize(creds) custom_setup(creds) if(creds.is_a?(Hash)) load_data(creds) else raise TypeError.new "Expecting `credentials` to be of type `Hash`. Received: `#{creds.class}`" end after_setup(creds) connect end |
Instance Method Details
#after_setup(creds) ⇒ TrueClass
Simple hook for concrete APIs to make adjustments after attribute population and prior to connection
46 47 48 |
# File 'lib/miasma/types/api.rb', line 46 def after_setup(creds) true end |
#api_for(type) ⇒ Api
Build new API for specified type using current provider / creds
66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/miasma/types/api.rb', line 66 def api_for(type) memoize(type) do Miasma.api( Smash.new( :type => type, :provider => provider, :credentials => attributes ) ) end end |
#connect ⇒ self
Connect to the remote API
58 59 60 |
# File 'lib/miasma/types/api.rb', line 58 def connect self end |
#connection ⇒ HTTP
79 80 81 |
# File 'lib/miasma/types/api.rb', line 79 def connection HTTP.headers('User-Agent' => "miasma/v#{Miasma::VERSION}") end |
#custom_setup(creds) ⇒ TrueClass
Simple hook for concrete APIs to make adjustments prior to initialization and connection
37 38 39 |
# File 'lib/miasma/types/api.rb', line 37 def custom_setup(creds) true end |
#endpoint ⇒ String
Returns url endpoint.
84 85 86 |
# File 'lib/miasma/types/api.rb', line 84 def endpoint 'http://api.example.com' end |
#format_response(result, extract_body = true) ⇒ Smash
Makes best attempt at formatting response
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/miasma/types/api.rb', line 183 def format_response(result, extract_body=true) extracted_headers = Smash[result.headers.map{|k,v| [Utils.snake(k), v]}] if(extract_body) body_content = result.body.to_s body_content.encode!('UTF-8', 'binary', :invalid => :replace, :undef => :replace, :replace => '' ) if(extracted_headers[:content_type].to_s.include?('json')) extracted_body = from_json(body_content) || body_content elsif(extracted_headers[:content_type].to_s.include?('xml')) extracted_body = from_xml(body_content) || body_content else extracted_body = from_json(body_content) || from_xml(body_content) || body_content end end unless(extracted_body) # @note if body is over 100KB, do not extract if(extracted_headers[:content_length].to_i < 102400) extracted_body = result.body.to_s else extracted_body = result.body end end Smash.new( :response => result, :headers => extracted_headers, :body => extracted_body ) end |
#from_json(string) ⇒ Hash, ...
Convert from JSON
221 222 223 224 225 226 227 |
# File 'lib/miasma/types/api.rb', line 221 def from_json(string) begin MultiJson.load(string).to_smash rescue MultiJson::ParseError nil end end |
#from_xml(string) ⇒ Hash, ...
Convert from JSON
233 234 235 236 237 238 239 |
# File 'lib/miasma/types/api.rb', line 233 def from_xml(string) begin MultiXml.parse(string).to_smash rescue MultiXml::ParseError nil end end |
#make_request(connection, http_method, request_args) ⇒ HTTP::Response
this is mainly here for concrete APIs to override if things need to be done prior to the actual request (like signature generation)
Perform request
174 175 176 |
# File 'lib/miasma/types/api.rb', line 174 def make_request(connection, http_method, request_args) connection.send(http_method, *request_args) end |
#perform_request_retry(exception) ⇒ TrueClass, FalseClass
Determine if a retry on the request should be performed
161 162 163 |
# File 'lib/miasma/types/api.rb', line 161 def perform_request_retry(exception) true end |
#provider ⇒ Symbol
Returns name of provider.
51 52 53 |
# File 'lib/miasma/types/api.rb', line 51 def provider Utils.snake(self.class.to_s.split('::').last).to_sym end |
#request(args) ⇒ Smash
Perform request to remote API
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/miasma/types/api.rb', line 97 def request(args) args = args.to_smash http_method = args.fetch(:method, 'get').to_s.downcase.to_sym unless(HTTP::Request::METHODS.include?(http_method)) raise ArgumentError.new 'Invalid request method provided!' end request_args = [].tap do |ary| _endpoint = args.delete(:endpoint) || endpoint ary.push( File.join(_endpoint, args[:path].to_s) ) = {}.tap do |opts| [:form, :params, :json, :body].each do |key| opts[key] = args[key] if args[key] end end ary.push() unless .empty? end if(args[:headers]) _connection = connection.headers(args[:headers]) args.delete(:headers) else _connection = connection end result = retryable_request(http_method) do res = make_request(_connection, http_method, request_args) unless([args.fetch(:expects, 200)].flatten.compact.map(&:to_i).include?(res.code)) raise Error::ApiError::RequestError.new(res.reason, :response => res) end res end format_response(result, !args[:disable_body_extraction]) end |
#retryable_allowed?(http_method) ⇒ TrueClass, FalseClass
Determine if request type is allowed to be retried
153 154 155 |
# File 'lib/miasma/types/api.rb', line 153 def retryable_allowed?(http_method) VALID_REQUEST_RETRY_METHODS.include?(http_method) end |
#retryable_request(http_method) { ... } ⇒ Object
If HTTP request method is allowed to be retried then retry request on non-response failures. Otherwise just re-raise immediately
138 139 140 141 142 143 144 145 146 147 |
# File 'lib/miasma/types/api.rb', line 138 def retryable_request(http_method, &block) Bogo::Retry.build( data.fetch(:retry_type, :exponential), :max_attempts => retryable_allowed?(http_method) ? data.fetch(:retry_max, MAX_REQUEST_RETRIES) : 0, :wait_interval => data[:retry_interval], :ui => data[:retry_ui], :auto_run => false, &block ).run!{|e| perform_request_retry(e) } end |