Skip to content

Commit 3e42f85

Browse files
committed
RUBYAPI-39 add request_path to ClientError
The downstream clients are able to glean API error codes, messages, and statuses now, but there are certain circumstances where it's not clear which API request failed without turning debug logging on. This change attempts to offer a happy medium, where an API application can log the request path, HTTP status, and API error code without having to resort to an all-or-nothing logging approach.
1 parent 3bec1a9 commit 3e42f85

File tree

4 files changed

+37
-18
lines changed

4 files changed

+37
-18
lines changed

lib/spark_api/authentication/oauth2_impl/faraday_middleware.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def on_complete(env)
2727
# OAuth2 implementations and wouldn't hurt to log.
2828
auth_header_error = env[:request_headers]["WWW-Authenticate"]
2929
SparkApi.logger.warn { "Authentication error #{auth_header_error}" } unless auth_header_error.nil?
30-
raise ClientError, {:message => body["error"], :code =>0, :status => env[:status]}
30+
raise ClientError, {:message => body["error"], :code =>0, :status => env[:status], :request_path => env[:url]}
3131
end
3232
SparkApi.logger.debug { "[oauth2] Session=#{session.inspect}" }
3333
env[:body] = session
@@ -58,7 +58,7 @@ def on_complete(env)
5858
return
5959
end
6060
end
61-
raise ClientError, {:message => "Unable to process sparkbar token #{body.inspect}", :code =>0, :status => env[:status]}
61+
raise ClientError, {:message => "Unable to process sparkbar token #{body.inspect}", :code =>0, :status => env[:status], :request_path => env[:url]}
6262
end
6363

6464
end

lib/spark_api/errors.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ module ResponseCodes
2121
# Errors built from API responses
2222
class InvalidResponse < StandardError; end
2323
class ClientError < StandardError
24-
attr_reader :code, :status, :details
24+
attr_reader :code, :status, :details, :request_path
2525
def initialize (options = {})
2626
# Support the standard initializer for errors
2727
opts = options.is_a?(Hash) ? options : {:message => options.to_s}
2828
@code = opts[:code]
2929
@status = opts[:status]
3030
@details = opts[:details]
31+
@request_path = opts[:request_path]
3132
super(opts[:message])
3233
end
3334

@@ -45,4 +46,4 @@ def self.ssl_verification_error
4546
"set 'ssl_verify' to false in the configuration or add '--no_verify' to the CLI command."
4647
end
4748
end
48-
end
49+
end

lib/spark_api/faraday_middleware.rb

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ def initialize(app)
1515
# Handles pretty much all the api response parsing and error handling. All responses that
1616
# indicate a failure will raise a SparkApi::ClientError exception
1717
def on_complete(env)
18-
1918
env[:body] = decompress_body(env)
2019

2120
body = MultiJson.decode(env[:body])
@@ -25,6 +24,7 @@ def on_complete(env)
2524
end
2625
response = ApiResponse.new body
2726
paging = response.pagination
27+
2828
if paging.nil?
2929
results = response
3030
else
@@ -35,34 +35,40 @@ def on_complete(env)
3535
results = paginate_response(response, paging)
3636
end
3737
end
38+
39+
error_hash = {
40+
:request_path => env[:url],
41+
:message => response.message,
42+
:code => response.code,
43+
:status => env[:status]
44+
}
45+
3846
case env[:status]
3947
when 400
40-
hash = {:message => response.message, :code => response.code, :status => env[:status]}
41-
4248
# constraint violation
4349
if response.code == 1053
4450
details = body['D']['Details']
45-
hash[:details] = details
51+
error_hash[:details] = details
4652
end
47-
raise BadResourceRequest,hash
53+
raise BadResourceRequest, error_hash
4854
when 401
4955
# Handle the WWW-Authenticate Response Header Field if present. This can be returned by
5056
# OAuth2 implementations and wouldn't hurt to log.
5157
auth_header_error = env[:request_headers]["WWW-Authenticate"]
5258
SparkApi.logger.warn("Authentication error #{auth_header_error}") unless auth_header_error.nil?
53-
raise PermissionDenied, {:message => response.message, :code => response.code, :status => env[:status]}
59+
raise PermissionDenied, error_hash
5460
when 404
55-
raise NotFound, {:message => response.message, :code => response.code, :status => env[:status]}
61+
raise NotFound, error_hash
5662
when 405
57-
raise NotAllowed, {:message => response.message, :code => response.code, :status => env[:status]}
63+
raise NotAllowed, error_hash
5864
when 409
59-
raise BadResourceRequest, {:message => response.message, :code => response.code, :status => env[:status]}
65+
raise BadResourceRequest, error_hash
6066
when 500
61-
raise ClientError, {:message => response.message, :code => response.code, :status => env[:status]}
67+
raise ClientError, error_hash
6268
when 200..299
6369
SparkApi.logger.debug { "Success!" }
6470
else
65-
raise ClientError, {:message => response.message, :code => response.code, :status => env[:status]}
71+
raise ClientError, error_hash
6672
end
6773
env[:body] = results
6874
end

spec/unit/spark_api/request_spec.rb

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
describe SparkApi do
44
describe SparkApi::ClientError do
5-
subject { SparkApi::ClientError.new({:message=>"OMG FAIL", :code=>1234, :status=>500}) }
5+
subject { SparkApi::ClientError.new({:message=>"OMG FAIL", :code=>1234, :status=>500, :request_path => '/v1/foo'}) }
66
it "should print a helpful to_s" do
77
subject.to_s.should == "OMG FAIL"
88
subject.message.should == "OMG FAIL"
@@ -13,6 +13,11 @@
1313
it "should have an http status" do
1414
subject.status.should == 500
1515
end
16+
17+
it "should have a request_path" do
18+
subject.request_path.should == '/v1/foo'
19+
end
20+
1621
it "should raise and exception with attached message" do
1722
expect { raise subject.class, {:message=>"My Message", :code=>1000, :status=>404}}.to raise_error(SparkApi::ClientError) do |e|
1823
e.message.should == "My Message"
@@ -339,12 +344,19 @@ def reauthenticated
339344
r
340345
end
341346
it "should fail horribly on a get" do
342-
expect { subject.get('/system')}.to raise_error(SparkApi::PermissionDenied){ |e| e.code.should == SparkApi::ResponseCodes::SESSION_TOKEN_EXPIRED }
347+
expect { subject.get('/system')}.to raise_error(SparkApi::PermissionDenied) do |e|
348+
e.code.should == SparkApi::ResponseCodes::SESSION_TOKEN_EXPIRED
349+
e.request_path.should == '/system'
350+
end
343351
subject.reauthenticated.should == 2
352+
344353
end
345354
it "should fail horribly on a post" do
346355
data = {"Contacts" => [{"DisplayName"=>"Wades Contact","PrimaryEmail"=>"wade11@fbsdata.com"}]}
347-
expect { subject.post('/contacts', data)}.to raise_error(SparkApi::PermissionDenied){ |e| e.code.should == SparkApi::ResponseCodes::SESSION_TOKEN_EXPIRED }
356+
expect { subject.post('/contacts', data)}.to raise_error(SparkApi::PermissionDenied) do |e|
357+
e.code.should == SparkApi::ResponseCodes::SESSION_TOKEN_EXPIRED
358+
e.request_path.should == '/contacts'
359+
end
348360
subject.reauthenticated.should == 2
349361
end
350362
end

0 commit comments

Comments
 (0)