зеркало из https://github.com/arthurnn/twirp-ruby.git
Handle errors: allow to return Twirp::Error from handlers, and also raise Twitp::Error exceptions
This commit is contained in:
Родитель
5561ff4564
Коммит
ff72884a74
|
@ -29,7 +29,12 @@ module Twirp
|
|||
ERROR_CODES = ERROR_CODES_TO_HTTP_STATUS.keys
|
||||
|
||||
# Twirp::Error represents a valid error from a Twirp service
|
||||
class Error
|
||||
class Error < StandardError
|
||||
|
||||
# Wrap an arbitrary error as a Twirp :internal
|
||||
def self.InternalWith(err)
|
||||
self.new :internal, err.message, "cause" => err.class.name
|
||||
end
|
||||
|
||||
# Initialize a Twirp::Error
|
||||
# The code MUST be one of the valid ERROR_CODES Symbols (e.g. :internal, :not_found, :permission_denied ...).
|
||||
|
@ -74,6 +79,10 @@ module Twirp
|
|||
JSON.generate(as_json)
|
||||
end
|
||||
|
||||
def to_s
|
||||
"Twirp::Error code:#{code} msg:#{msg.inspect} meta:#{meta.inspect}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_code(code)
|
||||
|
@ -99,7 +108,7 @@ module Twirp
|
|||
|
||||
def validate_meta_key_value(key, value)
|
||||
if !key.is_a?(String) || !value.is_a?(String)
|
||||
raise ArgumentError.new("Twirp::Error meta must be a Hash with String keys and values")
|
||||
raise ArgumentError.new("Twirp::Error meta must be a Hash with String keys and values. Invalid key<#{key.class}>: #{key.inspect}, value<#{value.class}>: #{value.inspect}")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -85,15 +85,23 @@ module Twirp
|
|||
|
||||
# Rack app handler.
|
||||
def call(env)
|
||||
req = Rack::Request.new(env)
|
||||
rpc, content_type, bad_route = parse_rack_request(req)
|
||||
if bad_route
|
||||
return error_response(bad_route)
|
||||
begin
|
||||
req = Rack::Request.new(env)
|
||||
rpc, content_type, bad_route = parse_rack_request(req)
|
||||
if bad_route
|
||||
return error_response(bad_route)
|
||||
end
|
||||
|
||||
proto_req = decode_request(rpc[:request_class], content_type, req.body.read)
|
||||
resp = @handler.send(rpc[:handler_method], proto_req)
|
||||
return rack_response_from_handler(rpc, content_type, resp)
|
||||
|
||||
rescue Twirp::Error => twerr
|
||||
error_response(twerr)
|
||||
rescue StandardError => err
|
||||
puts err.backtrace
|
||||
error_response(Twirp::Error.InternalWith(err))
|
||||
end
|
||||
|
||||
proto_req = decode_request(rpc[:request_class], content_type, req.body.read)
|
||||
resp = @handler.send(rpc[:handler_method], proto_req)
|
||||
return rack_response_from_handler(rpc, content_type, resp)
|
||||
end
|
||||
|
||||
def path_prefix
|
||||
|
|
|
@ -133,7 +133,7 @@ class ServiceTest < Minitest::Test
|
|||
status, headers, body = haberdasher_service.call(env)
|
||||
|
||||
assert_equal 404, status
|
||||
assert_equal 'application/json', headers['Content-Type'] # error messages are always JSON, even for Protobuf requests
|
||||
assert_equal 'application/json', headers['Content-Type'] # error responses are always JSON, even for Protobuf requests
|
||||
assert_equal({
|
||||
"code" => 'bad_route',
|
||||
"msg" => 'Invalid route. Expected format: POST {BaseURL}/twirp/(package.)?{Service}/{Method}',
|
||||
|
@ -180,6 +180,38 @@ class ServiceTest < Minitest::Test
|
|||
assert_equal Example::Hat.new(inches: 0, color: ""), Example::Hat.decode(body[0])
|
||||
end
|
||||
|
||||
# Handler should be able to return Twirp::Exception values, that will trigger error responses
|
||||
def test_handler_returns_twirp_exception
|
||||
svc = Example::Haberdasher.new(HaberdasherHandler.new do |size|
|
||||
return Twirp::Error.new(:invalid_argument, "I don't like that size")
|
||||
end)
|
||||
|
||||
env = proto_req "/twirp/example.Haberdasher/MakeHat", Example::Size.new(inches: 666)
|
||||
status, headers, body = svc.call(env)
|
||||
assert_equal 400, status
|
||||
assert_equal 'application/json', headers['Content-Type'] # error responses are always JSON, even for Protobuf requests
|
||||
assert_equal({
|
||||
"code" => 'invalid_argument',
|
||||
"msg" => "I don't like that size",
|
||||
}, JSON.parse(body[0]))
|
||||
end
|
||||
|
||||
# Handler should be able to raise a Twirp::Exception, that will trigger error responses
|
||||
def test_handler_raises_twirp_exception
|
||||
svc = Example::Haberdasher.new(HaberdasherHandler.new do |size|
|
||||
raise Twirp::Error.new(:invalid_argument, "I don't like that size")
|
||||
end)
|
||||
|
||||
env = proto_req "/twirp/example.Haberdasher/MakeHat", Example::Size.new(inches: 666)
|
||||
status, headers, body = svc.call(env)
|
||||
assert_equal 400, status
|
||||
assert_equal 'application/json', headers['Content-Type'] # error responses are always JSON, even for Protobuf requests
|
||||
assert_equal({
|
||||
"code" => 'invalid_argument',
|
||||
"msg" => "I don't like that size",
|
||||
}, JSON.parse(body[0]))
|
||||
end
|
||||
|
||||
|
||||
# Test Helpers
|
||||
# ------------
|
||||
|
|
Загрузка…
Ссылка в новой задаче