Class: Chimps::Request
- Defined in:
- lib/chimps/request.rb
Overview
A class to encapsulate requests made of Infochimps.
Essentialy a wrapper for RestClient::Resource with added funcionality for automatically signing requests and parsing Infochimps API responses.
Direct Known Subclasses
Constant Summary collapse
- DEFAULT_HEADERS =
Default headers to pass with every request.
{ :content_type => 'application/json', :accept => 'application/json', :user_agent => "Chimps #{Chimps.version}" }
Instance Attribute Summary collapse
-
#body ⇒ Object
Data to include in the body of the request.
-
#path ⇒ Object
Path of the URL to submit to.
-
#query_params ⇒ Object
Parameters to include in the query string of the URL to submit to.
Instance Method Summary collapse
-
#authenticable? ⇒ true, false
(also: #signable?)
Is this request authentiable (has the Chimps user specified an API key and secret in their configuration file)?.
-
#authenticate? ⇒ true, false
(also: #sign?)
Should the request be authenticated?.
-
#authenticate_if_necessary! ⇒ Object
Authenticate this request by stuffing the
:requested_at
and:apikey
properties into its:query_params
hash. -
#base_url ⇒ String
Return the base URL for this request, consisting of the host and path but not the query string.
-
#delete(options = {}, &block) ⇒ Chimps::Response
Perform a DELETE request to this URL, returning a parsed response.
- #encode(obj) ⇒ Object
-
#encoded_body ⇒ String
Return this Requests’s body as a suitably encoded string.
-
#get(options = {}, &block) ⇒ Chimps::Response
Perform a GET request to this URL, returning a parsed response.
-
#handle_exceptions(&block) ⇒ Object
Yield to
block
but rescue any RestClient errors by wrapping them in a Chimps::Response. -
#host ⇒ String
The host to send requests to.
-
#initialize(path, options = {}) ⇒ Chimps::Request
constructor
Initialize a Request to the given
path
. -
#obj_to_stripped_string(obj) ⇒ String
Turn
obj
into a string, sorting on internal keys. -
#post(options = {}, &block) ⇒ Chimps::Response
Perform a POST request to this URL, returning a parsed response.
-
#put(options = {}, &block) ⇒ Chimps::Response
Perform a PUT request to this URL, returning a parsed response.
-
#query_string ⇒ String
Return the query string for this request, signed if necessary.
-
#raw? ⇒ true, false
Should this be considered a raw request in which neither the query string nor the body should be encoded or escaped?.
-
#should_encode? ⇒ true, false
Should the query string and request body be encoded?.
-
#sign(string) ⇒ String
Sign
string
by concatenting it with the secret and computing the MD5 digest of the whole thing. -
#signed_query_string ⇒ String
Append the signature to the unsigned query string.
-
#unsigned_query_string ⇒ String
Return an unsigned query string for this request.
-
#unsigned_query_string_stripped ⇒ String
Return an unsigned query string for this request without the
&
and=
characters. -
#url_with_query_string ⇒ String
Return the URL for this request with the (signed, if necessary) query string appended.
Constructor Details
#initialize(path, options = {}) ⇒ Chimps::Request
Initialize a Request to the given path
.
Query parameters and data can be passed in as hashes named :params
and :body
, respectively.
If :sign
is passed in the options
then the URL of this request will be signed with the Chimps user’s Infochimps API key and secret. Signing a request which doesn’t need to be signed is just fine. Forgetting to sign a request which needs to be signed will result in a 401 error from Infochimps.
If :sign_if_possible
is passed in the options
then an attemp to sign the URL will be made though an error will not raise an error.
50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/chimps/request.rb', line 50 def initialize path, ={} self.path = path self.query_params = [:query_params] || [:query] || [:params] || {} self.body = [:body] || [:data] || {} @authentication_required = [:authenticate, :authenticated, :authenticate_if_possible, :sign, :signed, :sign_if_possible].any? { |key| [key] } @forgive_authentication_error = [:sign_if_possible] || [:authenticate_if_possible] @raw = [:raw] authenticate_if_necessary! super(url_with_query_string, {:headers => DEFAULT_HEADERS.merge([:headers] || {})}) end |
Instance Attribute Details
#body ⇒ Object
Data to include in the body of the request. Can be a Hash or a String.
25 26 27 |
# File 'lib/chimps/request.rb', line 25 def body @body end |
#path ⇒ Object
Path of the URL to submit to. Must be a String. Can start with an initial ‘/’ or not – no big deal ;)
17 18 19 |
# File 'lib/chimps/request.rb', line 17 def path @path end |
#query_params ⇒ Object
Parameters to include in the query string of the URL to submit to. Can be a string or a Hash
21 22 23 |
# File 'lib/chimps/request.rb', line 21 def query_params @query_params end |
Instance Method Details
#authenticable? ⇒ true, false Also known as: signable?
Is this request authentiable (has the Chimps user specified an API key and secret in their configuration file)?
104 105 106 |
# File 'lib/chimps/request.rb', line 104 def authenticable? Chimps.config[:catalog][:key] && Chimps.config[:catalog][:secret] end |
#authenticate? ⇒ true, false Also known as: sign?
Should the request be authenticated?
77 78 79 |
# File 'lib/chimps/request.rb', line 77 def authenticate? @authentication_required end |
#authenticate_if_necessary! ⇒ Object
Authenticate this request by stuffing the :requested_at
and :apikey
properties into its :query_params
hash.
Will do nothing at all if Chimps::Request#authenticate? returns false.
204 205 206 207 208 209 |
# File 'lib/chimps/request.rb', line 204 def authenticate_if_necessary! return unless authenticate? && should_encode? raise Chimps::AuthenticationError.new("Catalog API key (Chimps.config[:catalog][:key]) or secret (Chimps.config[:catalog][:secret]) missing from #{Chimps.config[:config]} or #{Chimps.config[:site_config]}") unless (authenticable? || @forgive_authentication_error) query_params[:requested_at] = Time.now.to_i.to_s query_params[:apikey] = Chimps.config[:catalog][:key] end |
#base_url ⇒ String
Return the base URL for this request, consisting of the host and path but not the query string.
120 121 122 |
# File 'lib/chimps/request.rb', line 120 def base_url File.join(host, path) end |
#delete(options = {}, &block) ⇒ Chimps::Response
Perform a DELETE request to this URL, returning a parsed response.
Any headers in options
will passed to RestClient::Resource.delete.
181 182 183 184 185 186 |
# File 'lib/chimps/request.rb', line 181 def delete ={}, &block handle_exceptions do Chimps.log.info("DELETE #{url}") Response.new(super(, &block)) end end |
#encode(obj) ⇒ Object
238 239 240 241 |
# File 'lib/chimps/request.rb', line 238 def encode obj require 'json' JSON.generate((obj == true ? {} : obj), {:max_nesting => false}) end |
#encoded_body ⇒ String
Return this Requests’s body as a suitably encoded string.
This is the text that will be signed for POST and PUT requests.
234 235 236 |
# File 'lib/chimps/request.rb', line 234 def encoded_body @encoded_body ||= should_encode? ? encode(body) : body.to_s end |
#get(options = {}, &block) ⇒ Chimps::Response
Perform a GET request to this URL, returning a parsed response.
Any headers in options
will passed to RestClient::Resource.get.
138 139 140 141 142 143 |
# File 'lib/chimps/request.rb', line 138 def get ={}, &block handle_exceptions do Chimps.log.info("GET #{url}") Response.new(super(, &block)) end end |
#handle_exceptions(&block) ⇒ Object
Yield to block
but rescue any RestClient errors by wrapping them in a Chimps::Response.
190 191 192 193 194 195 196 |
# File 'lib/chimps/request.rb', line 190 def handle_exceptions &block begin yield rescue RestClient::Exception => e Response.new(e.response, :error => e.) end end |
#host ⇒ String
The host to send requests to.
112 113 114 |
# File 'lib/chimps/request.rb', line 112 def host @host ||= Chimps.config[:catalog][:host] end |
#obj_to_stripped_string(obj) ⇒ String
Turn obj
into a string, sorting on internal keys.
273 274 275 276 277 278 279 |
# File 'lib/chimps/request.rb', line 273 def obj_to_stripped_string obj case obj when Hash then obj.keys.map(&:to_s).sort.map { |key| [key.to_s.downcase, obj_to_stripped_string(obj[key.to_sym])].join('') }.join('') when Array then obj.map { |e| obj_to_stripped_string(e) }.join('') else obj.to_s end end |
#post(options = {}, &block) ⇒ Chimps::Response
Perform a POST request to this URL, returning a parsed response.
Any headers in options
will passed to RestClient::Resource.post.
152 153 154 155 156 157 |
# File 'lib/chimps/request.rb', line 152 def post ={}, &block handle_exceptions do Chimps.log.info("POST #{url}") Response.new(super(encoded_body, , &block)) end end |
#put(options = {}, &block) ⇒ Chimps::Response
Perform a PUT request to this URL, returning a parsed response.
Any headers in options
will passed to RestClient::Resource.put.
166 167 168 169 170 171 |
# File 'lib/chimps/request.rb', line 166 def put ={}, &block handle_exceptions do Chimps.log.info("PUT #{url}") Response.new(super(encoded_body, , &block)) end end |
#query_string ⇒ String
Return the query string for this request, signed if necessary.
127 128 129 |
# File 'lib/chimps/request.rb', line 127 def query_string (authenticate? && authenticable?) ? signed_query_string : unsigned_query_string end |
#raw? ⇒ true, false
Should this be considered a raw request in which neither the query string nor the body should be encoded or escaped?
96 97 98 |
# File 'lib/chimps/request.rb', line 96 def raw? !!@raw end |
#should_encode? ⇒ true, false
Should the query string and request body be encoded?
Control this by passing in the :raw
keyword when initializing this Request.
88 89 90 |
# File 'lib/chimps/request.rb', line 88 def should_encode? !@raw end |
#sign(string) ⇒ String
Sign string
by concatenting it with the secret and computing the MD5 digest of the whole thing.
248 249 250 251 252 |
# File 'lib/chimps/request.rb', line 248 def sign string raise Chimps::AuthenticationError.new("No Catalog API secret stored in #{Chimps.config[:config]} or #{Chimps.config[:site_config]}. Set Chimps.config[:catalog][:secret].") unless (authenticable? || @forgive_authentication_error) require 'digest/md5' Digest::MD5.hexdigest(string + Chimps.config[:catalog][:secret]) end |
#signed_query_string ⇒ String
Append the signature to the unsigned query string.
The signature made from the Chimps user’s API secret and either the query string text (stripped of &
and =
) for GET and DELETE requests or the request body for POST and PUT requests.
262 263 264 265 266 267 |
# File 'lib/chimps/request.rb', line 262 def signed_query_string return unsigned_query_string unless should_encode? text_to_sign = ((body == true || (! body.empty?)) ? encoded_body : unsigned_query_string_stripped) signature = sign(text_to_sign) "#{unsigned_query_string}&signature=#{signature}" end |
#unsigned_query_string ⇒ String
Return an unsigned query string for this request.
214 215 216 |
# File 'lib/chimps/request.rb', line 214 def unsigned_query_string (should_encode? ? RestClient::Payload.generate(query_params) : query_params).to_s end |
#unsigned_query_string_stripped ⇒ String
Return an unsigned query string for this request without the &
and =
characters.
This is the text that will be signed for GET and DELETE requests.
225 226 227 |
# File 'lib/chimps/request.rb', line 225 def unsigned_query_string_stripped @query_params_text ||= obj_to_stripped_string(query_params) end |
#url_with_query_string ⇒ String
Return the URL for this request with the (signed, if necessary) query string appended.
66 67 68 69 70 71 72 |
# File 'lib/chimps/request.rb', line 66 def url_with_query_string if query_string && query_string.size > 0 base_url + "?#{query_string}" else base_url end end |