-
Notifications
You must be signed in to change notification settings - Fork 9
Services return the HTTP call's status #52
Conversation
/cc @calavera |
It looks good. I guess you've already seen how to extend services to store data in codeclimate, but just in case, check the pull request service extension out: https://github.com/codeclimate/codeclimate/blob/master/lib/cc/services/extensions/github_pull_requests.rb |
I have seen that, but I think these things should happen in this gem and not in an extension. Right? |
Right, the response still needs to be handled in the services gem. |
@@ -15,6 +15,34 @@ def default_http_options | |||
end | |||
end | |||
|
|||
def post(url, body = nil, headers = nil, &block) | |||
begin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this begin
is not necessary, either it is the end
that goes with it.
82b505e
to
d84ea34
Compare
f6d7999
to
66215e9
Compare
endpoint_url: url, | ||
exception_message: "#{e.class}: #{e.message}" | ||
} | ||
rescue Exception => e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably only rescue StandardError
type exceptions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Damnit, you're right. I'm usually the one catching this on others' code, too.
The way this works is by moving all of the actual HTTP POSTing into a dedicated method that wraps the response and also handles failures. A successful request will be parsed for standard things like status code, the params we sent, the url we hit, and whether it worked or not. An HTTP error will also include the exception message. Any other error will forego the HTTP code. This is all tested and common to each service, so they don't need their own specific tests for it. A successful request can be modified by adding extra attributes into the hash via a block. The response body is passed to the block (since we get both JSON and XML from various services). Relevant values can be extracted in this block. Parse errors will trigger the generic error handling and return a "this failed" message to the caller. The uniquely-added attributes are tested on a per-service basis. Some services make multiple requests. Only the last one is cared about. |
endpoint_url: url, | ||
exception_message: "#{e.class}: #{e.message}" | ||
} | ||
rescue *RERAISE_ERRORS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This pattern is making me a little quesy-- can we remove this special casing for test errors and make the following rescue for StandardError
more specific so it doesn't catch test assertion errors?
69ba1b4
to
103c008
Compare
The places where |
rescue CC::Service::HTTPError => ex | ||
body = JSON.parse(ex.response_body) | ||
ex.user_message = body["errors"].map{|e| e["message"] }.join(" ") | ||
raise ex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A bit confusing to me - where does this exception get handled? Wonder if the ErrorHandling
middleware is encouraging handling logic through exceptions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's no so much logic as it is that we need to augment the exception. There's information that the receive_test
methods need to put into the replies that can't be handled any other way. That's why we're re-raising the error -- the WithErrorHandling
middleware handles the errors just fine, but the since the receive_test
handlers are user-facing, they want/need to put pretty messages on the data returned.
It's possible we also want to handle this in the web-side, though that will be a bit more complicated.
Questions:
/cc @jeffrafter |
|
We can discuss these more tomorrow.
|
endpoint_url: url, | ||
status: response.status, | ||
message: "Success" | ||
}.merge(block.call(response)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After looking at the code more, I now see that post
returns a hash but get
returns, as it did before, some kind of http response object. I think this mismatch in the API is confusing, which is why I'm trying to explore if there's a better place for "response generation" that exists outside of this class. See main thread.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, a GET should generate the same kind of response.
speak(formatter.format_test, "green") | ||
|
||
{ ok: true, message: "Test message sent" } | ||
rescue => ex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this rescue handled up the callstack? I think so... just confirming
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup! See above. :)
In order to properly record the data for ServiceEvents in codeclimate proper, we need to have the calls to the external services return something useful. The way this works is by moving all of the actual HTTP POSTing into a dedicated method that wraps the response. Failures are handled by the `WithErrorHandling` invocation middleware as normal. A successful request will be parsed for standard things like status code, the params we sent, the url we hit, and whether it worked or not, and a message. Failures will have a message explaining the error. `receive_test` methods will include a user-friendly error message. Any other error will forego HTTP information. This is all tested and common to each service, so they don't need their own specific tests for it. A successful request can be modified by adding extra attributes into the hash via a block. The response body is passed to the block to be parsed inside it (since we get both JSON and XML from various services). Relevant values can be extracted in this block. Parse errors will trigger the generic error handling and return a "this failed" message to the caller. The uniquely-added attributes are tested on a per-service basis. Some services make multiple requests. The first one to fail is what we return an error message for. If none fail, it's all good.
Both Asana and Github provide a nicer error message when something goes wrong. If we get that response body, use it by supplying it as a supplementary error message. If we have this message, prefer it to the "real" exception's message. We must still send the message we log, so that it's saved along with the event's data.
6407363
to
26312cc
Compare
Stubbing `POST`s in the main codeclimate repo gets confused with stubbing the #post method here. So, change this method.
Services return the HTTP call's status
In order to properly record the data for ServiceEvents in codeclimate
proper, we need to have the calls to the external services return
something useful. This is the first step toward that goal.