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- REQUEST_RETRY_DELAY =
Seconds to pause between retries
0.5
Instance Method Summary collapse
-
#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.
-
#provider ⇒ Symbol
Name of provider.
-
#request(args) ⇒ Smash
Perform request to remote API.
-
#retryable_request(http_method) { ... } ⇒ Object
If HTTP request method is allowed to be retried then retry request on non-response failures.
Methods included from Utils::Memoization
#_memo, #clear_memoizations!, #memoize, #unmemoize
Methods included from Utils::Lazy
Constructor Details
#initialize(creds) ⇒ self
Create new API connection
23 24 25 26 27 28 29 30 31 |
# 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 connect end |
Instance Method Details
#api_for(type) ⇒ Api
Build new API for specified type using current provider / creds
58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/miasma/types/api.rb', line 58 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
50 51 52 |
# File 'lib/miasma/types/api.rb', line 50 def connect self end |
#connection ⇒ HTTP
71 72 73 |
# File 'lib/miasma/types/api.rb', line 71 def connection HTTP.with_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
38 39 40 |
# File 'lib/miasma/types/api.rb', line 38 def custom_setup(creds) true end |
#endpoint ⇒ String
Returns url endpoint.
76 77 78 |
# File 'lib/miasma/types/api.rb', line 76 def endpoint 'http://api.example.com' end |
#format_response(result, extract_body = true) ⇒ Smash
Makes best attempt at formatting response
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/miasma/types/api.rb', line 162 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
200 201 202 203 204 205 206 |
# File 'lib/miasma/types/api.rb', line 200 def from_json(string) begin MultiJson.load(string).to_smash rescue MultiJson::ParseError nil end end |
#from_xml(string) ⇒ Hash, ...
Convert from JSON
212 213 214 215 216 217 218 |
# File 'lib/miasma/types/api.rb', line 212 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
153 154 155 |
# File 'lib/miasma/types/api.rb', line 153 def make_request(connection, http_method, request_args) connection.send(http_method, *request_args) end |
#provider ⇒ Symbol
Returns name of provider.
43 44 45 |
# File 'lib/miasma/types/api.rb', line 43 def provider Utils.snake(self.class.to_s.split('::').last).to_sym end |
#request(args) ⇒ Smash
Perform request to remote API
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/miasma/types/api.rb', line 89 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.with_headers(args[:headers]) args.delete(:headers) else _connection = connection end result = retryable_request(http_method) do make_request(_connection, http_method, request_args) end unless([args.fetch(:expects, 200)].flatten.compact.map(&:to_i).include?(result.code)) raise Error::ApiError::RequestError.new(result.reason, :response => result) end format_response(result, !args[:disable_body_extraction]) 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
129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/miasma/types/api.rb', line 129 def retryable_request(http_method) attempts = VALID_REQUEST_RETRY_METHODS.include?(http_method) ? 0 :nil begin yield rescue => e if(attempts && attempts < MAX_REQUEST_RETRIES) attempts += 1 sleep REQUEST_RETRY_DELAY retry else raise end end end |