Replies: 7 comments
-
Errors returned by endpoints should probably indicate transport errors that are worth retrying. That's because it's the only mechanism that safety-style middlewares like circuit breakers and rate limiters have to determine what to do with a given request. Business-domain errors should probably be baked in to your response struct, using whatever degree and depth of context is appropriate for you. I'm happy to work this into a FAQ entry, or look at your attempt to do the same. |
Beta Was this translation helpful? Give feedback.
-
Hey @ryan0x44! In my microservices, I return the error as part of the Endpoint's type errorer interface {
error() error
}
func encodeHTTPResponse(ctx context.Context, w http.ResponseWriter, response interface{}) error {
if e, ok := response.(errorer); ok && e.error() != nil {
err := e.error()
// encode HTTP error
return nil
}
// ...
} By this point the full error message has already been handled by logging middleware, so there's no additional work needed to log it here. |
Beta Was this translation helpful? Give feedback.
-
Thanks @peterbourgon and @terinjokes ! I'm still trying to grok how to handle logging the detailed error and returning the user-friendly error. Is "worth retrying" the best way to delineate these errors?
If so, could it be said that the former would be HTTP status codes not in 500, the latter would be HTTP status codes in the 500's? Examples:
|
Beta Was this translation helpful? Give feedback.
-
The HTTP spec includes discussions of which codes are intended to be retry-able and under what circumstances and mechanisms (e.g. the Ideally, any implementation would make it easy to follow the retry-able vs non-retry-able guidelines and mechanisms already present in HTTP. |
Beta Was this translation helpful? Give feedback.
-
Let's be more precise. If an error is returned by an endpoint, it's visible to endpoint middlewares and the transport layer; you can safely assume those layers might make decisions based on the presence of that error. If an error is enclosed in a response type, it's not visible‡ to endpoint middlewares or the transport layer; you can safely assume stock Go kit‡‡ won't make decisions based on the presence of that error.
These all make sense to me on a quick skim. — |
Beta Was this translation helpful? Give feedback.
-
I think many of those non-transport errors in @ryan0x44 's examples still do somewhat map into the response codes:
These database / business-domain / validation errors are additional information beyond the status code, which may be fairly specific (409) or very generic (400, 500). A 409 state conflict may show up as a database error (e.g. Foreign key constraint failure: you need to create object X before object Y, which can be fixed and retried). This is arguably more important to the client than the fact that the error occurred in the database (which is more important to the service developer). |
Beta Was this translation helpful? Give feedback.
-
Yes. Any reasonably sophisticated service will want to introspect response types to extract errors, and map them to HTTP response codes (or the equivalent in whatever other transport is being used). |
Beta Was this translation helpful? Give feedback.
-
As a service owner, I want as much information as possible about errors that occur, but I might not always want to reveal details to consumers of my service.
For example, say you service has a database error
pq: invalid input syntax for integer: \"b\"
.Right now, the Endpoint interface returns
interface{}, error
which means to add data such as an error code, we either need to do one of:I'm not sure how to best achieve this with Go kit, and feel like it's something Go kit could provide (more) guidance on. From this issue, I'm hoping to PR some documentation to help with that.
Beta Was this translation helpful? Give feedback.
All reactions