spark_api 1.4.24 → 1.4.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/VERSION +1 -1
- data/lib/spark_api/configuration.rb +3 -1
- data/lib/spark_api/connection.rb +19 -6
- data/lib/spark_api/errors.rb +2 -1
- data/lib/spark_api/faraday_middleware.rb +3 -1
- data/lib/spark_api/request.rb +1 -1
- data/lib/spark_api/response.rb +21 -11
- data/spec/unit/spark_api/configuration_spec.rb +32 -1
- data/spec/unit/spark_api/request_spec.rb +13 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YWRmNWJhNzE4N2I3MTU1Y2M5MjFlYWFmMGVkMjlhNjg1MTY2NTgyOA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MWViOWU1YjgzODg2NjgzZWQyOWI2MTcxZThkY2YxNWVhYmY1NTc5MA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Y2VlNjczMDNmMjQ2NGUwYmY0ZGNmMjFhOTRiZDg4OTJmYzAzYTgyZmE3ZTcz
|
10
|
+
Mzc4NzZjYTI2MzBmMjAwOGI2MTIzZmI1MTU4MzVjOGRhMTYyY2NhYTc2YjEy
|
11
|
+
NWUzZTNlYzRhMmFlZDhiM2M3NmFhNGVmZTM5ODdiMzcxMGE3NWY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MWQxOWQ0ODM3MTcyMjJkZTBlNTI1MmYyZWVjYzdhNzE2MzQzODNiOGEyZjVk
|
14
|
+
ZGZlNzUwNzg4Y2EyN2EyNTAyM2VmOTNiZjVmZjg0MjRjNDk1Y2YwYTAxZWVm
|
15
|
+
MzgwOTljMDVhZWI0MTE2YmNiMzIzYzBkYzJlNzFlZDRiYmYwY2Q=
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.4.
|
1
|
+
1.4.25
|
@@ -11,7 +11,7 @@ module SparkApi
|
|
11
11
|
# valid configuration options
|
12
12
|
VALID_OPTION_KEYS = [:api_key, :api_secret, :api_user, :endpoint,
|
13
13
|
:user_agent, :version, :ssl, :ssl_verify, :oauth2_provider, :authentication_mode,
|
14
|
-
:auth_endpoint, :callback, :compress, :timeout, :middleware].freeze
|
14
|
+
:auth_endpoint, :callback, :compress, :timeout, :middleware, :request_id_chain].freeze
|
15
15
|
OAUTH2_KEYS = [:authorization_uri, :access_uri, :client_id, :client_secret,
|
16
16
|
# Requirements for authorization_code grant type
|
17
17
|
:redirect_uri,
|
@@ -44,6 +44,7 @@ module SparkApi
|
|
44
44
|
DEFAULT_COMPRESS = false
|
45
45
|
DEFAULT_TIMEOUT = 5 # seconds
|
46
46
|
DEFAULT_MIDDLEWARE = 'spark_api'
|
47
|
+
DEFAULT_REQUEST_ID_CHAIN = nil
|
47
48
|
|
48
49
|
X_SPARK_API_USER_AGENT = "X-SparkApi-User-Agent"
|
49
50
|
|
@@ -78,6 +79,7 @@ module SparkApi
|
|
78
79
|
self.compress = DEFAULT_COMPRESS
|
79
80
|
self.timeout = DEFAULT_TIMEOUT
|
80
81
|
self.middleware = DEFAULT_MIDDLEWARE
|
82
|
+
self.request_id_chain = DEFAULT_REQUEST_ID_CHAIN
|
81
83
|
self
|
82
84
|
end
|
83
85
|
end
|
data/lib/spark_api/connection.rb
CHANGED
@@ -5,6 +5,15 @@ module SparkApi
|
|
5
5
|
# =Connection
|
6
6
|
# Mixin module for handling http connection information
|
7
7
|
module Connection
|
8
|
+
REG_HTTP = /^http:/
|
9
|
+
REG_HTTPS = /^https:/
|
10
|
+
HTTP_SCHEME = 'http:'
|
11
|
+
HTTPS_SCHEME = 'https:'
|
12
|
+
ACCEPT_ENCODING = 'Accept-Encoding'
|
13
|
+
COMPRESS_ACCEPT_ENCODING = 'gzip, deflate'
|
14
|
+
X_REQUEST_ID_CHAIN = 'X-Request-Id-Chain'
|
15
|
+
MIME_JSON = 'application/json'
|
16
|
+
MIME_RESO = 'application/json, application/xml'
|
8
17
|
# Main connection object for running requests. Bootstraps the Faraday abstraction layer with
|
9
18
|
# our client configuration.
|
10
19
|
def connection(force_ssl = false)
|
@@ -13,13 +22,17 @@ module SparkApi
|
|
13
22
|
}
|
14
23
|
if(force_ssl || self.ssl)
|
15
24
|
opts[:ssl] = {:verify => false } unless self.ssl_verify
|
16
|
-
opts[:url] = @endpoint.sub
|
25
|
+
opts[:url] = @endpoint.sub REG_HTTP, HTTPS_SCHEME
|
17
26
|
else
|
18
|
-
opts[:url] = @endpoint.sub
|
27
|
+
opts[:url] = @endpoint.sub REG_HTTPS, HTTP_SCHEME
|
19
28
|
end
|
20
29
|
|
21
30
|
if self.compress
|
22
|
-
opts[:headers][
|
31
|
+
opts[:headers][ACCEPT_ENCODING] = COMPRESS_ACCEPT_ENCODING
|
32
|
+
end
|
33
|
+
|
34
|
+
if request_id_chain
|
35
|
+
opts[:headers][X_REQUEST_ID_CHAIN] = request_id_chain
|
23
36
|
end
|
24
37
|
|
25
38
|
conn = Faraday.new(opts) do |conn|
|
@@ -42,8 +55,8 @@ module SparkApi
|
|
42
55
|
|
43
56
|
def spark_headers
|
44
57
|
{
|
45
|
-
:accept =>
|
46
|
-
:content_type =>
|
58
|
+
:accept => MIME_JSON,
|
59
|
+
:content_type => MIME_JSON,
|
47
60
|
:user_agent => Configuration::DEFAULT_USER_AGENT,
|
48
61
|
Configuration::X_SPARK_API_USER_AGENT => user_agent
|
49
62
|
}
|
@@ -51,7 +64,7 @@ module SparkApi
|
|
51
64
|
|
52
65
|
def reso_headers
|
53
66
|
{
|
54
|
-
:accept =>
|
67
|
+
:accept => MIME_RESO,
|
55
68
|
:user_agent => Configuration::DEFAULT_USER_AGENT,
|
56
69
|
Configuration::X_SPARK_API_USER_AGENT => user_agent
|
57
70
|
}
|
data/lib/spark_api/errors.rb
CHANGED
@@ -21,7 +21,7 @@ module SparkApi
|
|
21
21
|
# Errors built from API responses
|
22
22
|
class InvalidResponse < StandardError; end
|
23
23
|
class ClientError < StandardError
|
24
|
-
attr_reader :code, :status, :details, :request_path, :errors
|
24
|
+
attr_reader :code, :status, :details, :request_path, :request_id, :errors
|
25
25
|
def initialize (options = {})
|
26
26
|
# Support the standard initializer for errors
|
27
27
|
opts = options.is_a?(Hash) ? options : {:message => options.to_s}
|
@@ -29,6 +29,7 @@ module SparkApi
|
|
29
29
|
@status = opts[:status]
|
30
30
|
@details = opts[:details]
|
31
31
|
@request_path = opts[:request_path]
|
32
|
+
@request_id = opts[:request_id]
|
32
33
|
@errors = opts[:errors]
|
33
34
|
super(opts[:message])
|
34
35
|
end
|
@@ -22,7 +22,8 @@ module SparkApi
|
|
22
22
|
unless body.is_a?(Hash) && body.key?("D")
|
23
23
|
raise InvalidResponse, "The server response could not be understood"
|
24
24
|
end
|
25
|
-
|
25
|
+
request_id = env[:response_headers]['x-request-id']
|
26
|
+
response = ApiResponse.new body, request_id
|
26
27
|
paging = response.pagination
|
27
28
|
|
28
29
|
if paging.nil?
|
@@ -38,6 +39,7 @@ module SparkApi
|
|
38
39
|
|
39
40
|
error_hash = {
|
40
41
|
:request_path => env[:url],
|
42
|
+
:request_id => request_id,
|
41
43
|
:message => response.message,
|
42
44
|
:code => response.code,
|
43
45
|
:status => env[:status],
|
data/lib/spark_api/request.rb
CHANGED
@@ -79,7 +79,7 @@ module SparkApi
|
|
79
79
|
response = authenticator.request(method, request_path, post_data, request_opts)
|
80
80
|
end
|
81
81
|
request_time = Time.now - start_time
|
82
|
-
SparkApi.logger.debug { "[#{(request_time * 1000).to_i}ms] Api: #{method.to_s.upcase} #{request_path}" }
|
82
|
+
SparkApi.logger.debug { "[#{(request_time * 1000).to_i}ms] Api: #{method.to_s.upcase} #{request_path} request_id=#{response.headers['x-request-id']}" }
|
83
83
|
rescue PermissionDenied => e
|
84
84
|
if(ResponseCodes::SESSION_TOKEN_EXPIRED == e.code)
|
85
85
|
unless (attempts +=1) > 1
|
data/lib/spark_api/response.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module SparkApi
|
2
2
|
# API Response interface
|
3
3
|
module Response
|
4
|
-
ATTRIBUTES = [:code, :message, :results, :success, :pagination, :details, :d, :errors, :sparkql_errors]
|
4
|
+
ATTRIBUTES = [:code, :message, :results, :success, :pagination, :details, :d, :errors, :sparkql_errors, :request_id]
|
5
5
|
attr_accessor *ATTRIBUTES
|
6
6
|
def success?
|
7
7
|
@success
|
@@ -10,21 +10,31 @@ module SparkApi
|
|
10
10
|
|
11
11
|
# Nice and handy class wrapper for the api response hash
|
12
12
|
class ApiResponse < ::Array
|
13
|
+
MAGIC_D = 'D'
|
14
|
+
MESSAGE = 'Message'
|
15
|
+
CODE = 'Code'
|
16
|
+
RESULTS = 'Results'
|
17
|
+
SUCCESS = 'Success'
|
18
|
+
PAGINATION = 'Pagination'
|
19
|
+
DETAILS = 'Details'
|
20
|
+
ERRORS = 'Errors'
|
21
|
+
SPARKQL_ERRORS = 'SparkQLErrors'
|
13
22
|
include SparkApi::Response
|
14
|
-
def initialize
|
23
|
+
def initialize d, request_id=nil
|
15
24
|
begin
|
16
|
-
self.d = d[
|
25
|
+
self.d = d[MAGIC_D]
|
17
26
|
if self.d.nil? || self.d.empty?
|
18
27
|
raise InvalidResponse, "The server response could not be understood"
|
19
28
|
end
|
20
|
-
self.message = self.d[
|
21
|
-
self.code = self.d[
|
22
|
-
self.results = Array(self.d[
|
23
|
-
self.success = self.d[
|
24
|
-
self.pagination = self.d[
|
25
|
-
self.details = self.d[
|
26
|
-
self.errors = self.d[
|
27
|
-
self.sparkql_errors = self.d[
|
29
|
+
self.message = self.d[MESSAGE]
|
30
|
+
self.code = self.d[CODE]
|
31
|
+
self.results = Array(self.d[RESULTS])
|
32
|
+
self.success = self.d[SUCCESS]
|
33
|
+
self.pagination = self.d[PAGINATION]
|
34
|
+
self.details = self.d[DETAILS] || []
|
35
|
+
self.errors = self.d[ERRORS]
|
36
|
+
self.sparkql_errors = self.d[SPARKQL_ERRORS]
|
37
|
+
self.request_id = request_id
|
28
38
|
super(results)
|
29
39
|
rescue Exception => e
|
30
40
|
SparkApi.logger.error "Unable to understand the response! #{d}"
|
@@ -13,6 +13,7 @@ describe SparkApi::Client, "Client config" do
|
|
13
13
|
SparkApi.api_key = "my_api_key"
|
14
14
|
SparkApi.api_key.should match("my_api_key")
|
15
15
|
SparkApi.timeout.should eq(5)
|
16
|
+
SparkApi.request_id_chain.should be_nil
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
@@ -23,7 +24,8 @@ describe SparkApi::Client, "Client config" do
|
|
23
24
|
:api_user => "1234",
|
24
25
|
:auth_endpoint => "https://login.wade.dev.fbsdata.com",
|
25
26
|
:endpoint => "http://api.wade.dev.fbsdata.com",
|
26
|
-
:timeout => 15
|
27
|
+
:timeout => 15,
|
28
|
+
:request_id_chain => 'foobar')
|
27
29
|
|
28
30
|
client.api_key.should match("key_of_wade")
|
29
31
|
client.api_secret.should match("TopSecret")
|
@@ -32,6 +34,7 @@ describe SparkApi::Client, "Client config" do
|
|
32
34
|
client.endpoint.should match("http://api.wade.dev.fbsdata.com")
|
33
35
|
client.version.should match("v1")
|
34
36
|
client.timeout.should eq(15)
|
37
|
+
client.request_id_chain.should eq('foobar')
|
35
38
|
end
|
36
39
|
|
37
40
|
it "should allow unverified ssl certificates when verification is off" do
|
@@ -126,11 +129,14 @@ describe SparkApi::Client, "Client config" do
|
|
126
129
|
config.version = "veleventy"
|
127
130
|
config.endpoint = "test.api.sparkapi.com"
|
128
131
|
config.user_agent = "my useragent"
|
132
|
+
config.request_id_chain = 'foobar'
|
129
133
|
end
|
130
134
|
|
131
135
|
SparkApi.api_key.should match("my_key")
|
136
|
+
SparkApi.request_id_chain.should eq("foobar")
|
132
137
|
SparkApi.reset
|
133
138
|
SparkApi.api_key.should == SparkApi::Configuration::DEFAULT_API_KEY
|
139
|
+
SparkApi.request_id_chain.should SparkApi::Configuration::DEFAULT_REQUEST_ID_CHAIN
|
134
140
|
|
135
141
|
end
|
136
142
|
end
|
@@ -184,6 +190,31 @@ describe SparkApi::Client, "Client config" do
|
|
184
190
|
})
|
185
191
|
end
|
186
192
|
|
193
|
+
it "should pass along the request_id_chain header if set" do
|
194
|
+
reset_config
|
195
|
+
stub_auth_request
|
196
|
+
stub_request(:get, "#{SparkApi.endpoint}/#{SparkApi.version}/headers").
|
197
|
+
with(:query => {
|
198
|
+
:ApiUser => "foobar",
|
199
|
+
:ApiSig => "717a066c4f4302c5ca9507e484db4812",
|
200
|
+
:AuthToken => "c401736bf3d3f754f07c04e460e09573"
|
201
|
+
}).
|
202
|
+
to_return(:body => '{"D":{"Success": true,"Results": []}}')
|
203
|
+
SparkApi.configure do |config|
|
204
|
+
config.user_agent = "my useragent"
|
205
|
+
config.request_id_chain = 'foobar'
|
206
|
+
end
|
207
|
+
SparkApi.client.get '/headers'
|
208
|
+
WebMock.should have_requested(:get, "#{SparkApi.endpoint}/#{SparkApi.version}/headers?ApiUser=foobar&ApiSig=717a066c4f4302c5ca9507e484db4812&AuthToken=c401736bf3d3f754f07c04e460e09573").
|
209
|
+
with(:headers => {
|
210
|
+
'User-Agent' => SparkApi::Configuration::DEFAULT_USER_AGENT,
|
211
|
+
SparkApi::Configuration::X_SPARK_API_USER_AGENT => "my useragent",
|
212
|
+
'Accept'=>'application/json',
|
213
|
+
'Content-Type'=>'application/json',
|
214
|
+
'X-Request-Id-Chain' => 'foobar'
|
215
|
+
})
|
216
|
+
end
|
217
|
+
|
187
218
|
it "should not set gzip header by default" do
|
188
219
|
c = SparkApi::Client.new(:endpoint => "https://sparkapi.com")
|
189
220
|
c.connection.headers["Accept-Encoding"].should be_nil
|
@@ -2,7 +2,7 @@ require './spec/spec_helper'
|
|
2
2
|
|
3
3
|
describe SparkApi do
|
4
4
|
describe SparkApi::ClientError do
|
5
|
-
subject { SparkApi::ClientError.new({:message=>"OMG FAIL", :code=>1234, :status=>500, :request_path => '/v1/foo'}) }
|
5
|
+
subject { SparkApi::ClientError.new({:message=>"OMG FAIL", :code=>1234, :status=>500, :request_path => '/v1/foo', :request_id => 'deadbeef'}) }
|
6
6
|
it "should print a helpful to_s" do
|
7
7
|
subject.to_s.should == "OMG FAIL"
|
8
8
|
subject.message.should == "OMG FAIL"
|
@@ -18,6 +18,10 @@ describe SparkApi do
|
|
18
18
|
subject.request_path.should == '/v1/foo'
|
19
19
|
end
|
20
20
|
|
21
|
+
it "should have a request_id" do
|
22
|
+
subject.request_id.should == 'deadbeef'
|
23
|
+
end
|
24
|
+
|
21
25
|
it "should raise and exception with attached message" do
|
22
26
|
expect { raise subject.class, {:message=>"My Message", :code=>1000, :status=>404}}.to raise_error(SparkApi::ClientError) do |e|
|
23
27
|
e.message.should == "My Message"
|
@@ -38,6 +42,7 @@ describe SparkApi do
|
|
38
42
|
e.message.should == "My Message"
|
39
43
|
e.code.should be == nil
|
40
44
|
e.status.should be == nil
|
45
|
+
e.request_id.should be == nil
|
41
46
|
end
|
42
47
|
end
|
43
48
|
end
|
@@ -51,6 +56,13 @@ describe SparkApi do
|
|
51
56
|
r = SparkApi::ApiResponse.new({"D"=>{"Success" => true, "Results" => []}})
|
52
57
|
r.success?.should be(true)
|
53
58
|
r.results.empty?.should be(true)
|
59
|
+
r.request_id.should eq nil
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return the request_id" do
|
63
|
+
r = SparkApi::ApiResponse.new({"D"=>{"Success" => true, "Results" => []}}, 'foobar')
|
64
|
+
r.success?.should be(true)
|
65
|
+
r.request_id.should eq('foobar')
|
54
66
|
end
|
55
67
|
it "should have a message on error" do
|
56
68
|
r = SparkApi::ApiResponse.new({"D"=>{"Success" => false, "Message" => "I am a failure."}})
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spark_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.25
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Hornseth
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2018-06-
|
12
|
+
date: 2018-06-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: faraday
|