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
23 24 25 26 27 28 29 30 31 32 |
# File 'lib/miasma/types/api.rb', line 23 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
48 49 50 |
# File 'lib/miasma/types/api.rb', line 48 def after_setup(creds) true end |
#api_for(type) ⇒ Api
Build new API for specified type using current provider / creds
68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/miasma/types/api.rb', line 68 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
60 61 62 |
# File 'lib/miasma/types/api.rb', line 60 def connect self end |
#connection ⇒ HTTP
81 82 83 |
# File 'lib/miasma/types/api.rb', line 81 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
39 40 41 |
# File 'lib/miasma/types/api.rb', line 39 def custom_setup(creds) true end |
#endpoint ⇒ String
Returns url endpoint.
86 87 88 |
# File 'lib/miasma/types/api.rb', line 86 def endpoint 'http://api.example.com' end |
#format_response(result, extract_body = true) ⇒ Smash
Makes best attempt at formatting response
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 216 217 |
# File 'lib/miasma/types/api.rb', line 185 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
223 224 225 226 227 228 229 |
# File 'lib/miasma/types/api.rb', line 223 def from_json(string) begin MultiJson.load(string).to_smash rescue MultiJson::ParseError nil end end |
#from_xml(string) ⇒ Hash, ...
Convert from JSON
235 236 237 238 239 240 241 |
# File 'lib/miasma/types/api.rb', line 235 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
176 177 178 |
# File 'lib/miasma/types/api.rb', line 176 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
163 164 165 |
# File 'lib/miasma/types/api.rb', line 163 def perform_request_retry(exception) true end |
#provider ⇒ Symbol
Returns name of provider.
53 54 55 |
# File 'lib/miasma/types/api.rb', line 53 def provider Utils.snake(self.class.to_s.split('::').last).to_sym end |
#request(args) ⇒ Smash
Perform request to remote API
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 130 131 |
# File 'lib/miasma/types/api.rb', line 99 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
155 156 157 |
# File 'lib/miasma/types/api.rb', line 155 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
140 141 142 143 144 145 146 147 148 149 |
# File 'lib/miasma/types/api.rb', line 140 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 |