Introduce ServiceResponse#reason to distinguish between errors
Problem
The ServiceResponse#http_status
is a violation of a good Hexagonal architecture because it ties the result of a domain service (business logic) to how it should be rendered to the client. It should be the adapter’s responsibility (for example the REST/GraphQL/Controller endpoint) to decide what HTTP status to use.
Maybe we could use reason
or resolution
which we can set to a symbol that the caller can parse and decide how to react.
This can be a problem if we want to reuse a service object across 2 endpoints that return different HTTP statuses on error. Also having a way to choose how to react to a response error based on the reason (for example: a symbol) would be better than switching based on the http_status
or message
.
Proposal
- Introduce a
reason:
option in theServiceResponse
object. - Add static analyzer to block new usages of
http_status
. - Create issues to retire use of
http_status
in favour ofreason
.
class MyService
def execute
# do some work
rescue Gitlab::Access::AccessDeniedError => e
ServiceResponse.error(message: e.message, reason: :access_denied)
end
end
# how to use it?
response = MyService.new(...).execute
if response.success?
head :ok
elsif response.reason == :access_denied
head :forbidden
else
head :bad_request
end
Edited by Fabio Pitino