Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Wreq.get("not-a-valid-url")
rescue Wreq::Error => error
puts "#{error.class}: #{error.message}"
puts "builder: #{error.is_builder}"
puts "builder: #{error.builder?}"
puts "uri: #{error.uri.inspect}"
puts "status: #{error.status.inspect}"
end
66 changes: 47 additions & 19 deletions lib/wreq_ruby/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,24 @@ module Wreq
# Base class for wreq-ruby runtime errors.
#
# Error remains a RuntimeError so existing rescue handlers keep working.
# The `is_*` methods mirror predicates on the captured native `wreq::Error`.
# One error can match more than one predicate. Errors created by the binding
# itself return false for all of them.
# Its subclass records one primary category. Predicate methods retain every
# classification reported by the native `wreq::Error`, so more than one can
# be true. For example, a request timeout raises TimeoutError while both
# `timeout?` and `request?` return true.
#
# A native kind such as BodyError, TlsError, or StatusError takes precedence
# over details found in its cause chain. Native request errors are then
# classified as connection reset, timeout, proxy connection, destination
# connection, or RequestError, in that order. Use the predicates when code
# needs every native classification. Errors created by the binding itself
# return false for all of them.
#
# @example Rescue any wreq-ruby runtime error
# begin
# Wreq.get("not-a-valid-url")
# rescue Wreq::Error => error
# warn "#{error.class}: #{error.message}"
# warn "invalid request" if error.is_builder
# warn "invalid request" if error.builder?
# end
class Error < RuntimeError
# Get the URI recorded by the native error.
Expand All @@ -32,51 +40,57 @@ class Error < RuntimeError
attr_reader :status

# @return [Boolean] Whether the native error came from a builder
def is_builder
def builder?
end

# @return [Boolean] Whether the native error came from redirect handling
def is_redirect
def redirect?
end

# @return [Boolean] Whether the native error represents an HTTP status
def is_status
def status?
end

# A request timeout uses TimeoutError even when this is also a connection
# or proxy connection error.
#
# @return [Boolean] Whether the native error is related to a timeout
def is_timeout
def timeout?
end

# This may be true on connection and timeout subclasses because those
# errors occur while sending a request.
#
# @return [Boolean] Whether the native error is related to a request
def is_request
def request?
end

# @return [Boolean] Whether the native error is related to connecting
def is_connect
def connection?
end

# @return [Boolean] Whether the native error is related to a proxy connection
def is_proxy_connect
def proxy_connection?
end

# @return [Boolean] Whether the native error is a connection reset
def is_connection_reset
def connection_reset?
end

# @return [Boolean] Whether the native error is related to a body
def is_body
def body?
end

# @return [Boolean] Whether the native error is related to TLS
def is_tls
def tls?
end

# @return [Boolean] Whether the native error is related to decoding
def is_decode
def decoding?
end

# @return [Boolean] Whether the native error is related to an upgrade
def is_upgrade
def upgrade?
end
end

Expand Down Expand Up @@ -124,9 +138,10 @@ class ForkError < Error; end

# Raised when the client cannot connect to the destination server.
#
# The error reflects the layer that actually fails. If a system proxy or
# VPN accepts the connection but does not return a response, the request
# raises Wreq::TimeoutError instead.
# If the native error reports both a destination connection failure and a
# timeout, Wreq::TimeoutError is raised and `connection?` remains true. A
# system proxy or VPN that accepts the connection but never responds may
# instead appear as a general request timeout.
#
# @example Handle a destination connection failure
# client = Wreq::Client.new(no_proxy: true)
Expand All @@ -139,6 +154,9 @@ class ConnectionError < Error; end

# Raised when the client cannot connect to the configured proxy.
#
# If the native error reports both a proxy connection failure and a timeout,
# Wreq::TimeoutError is raised and `proxy_connection?` remains true.
#
# @example Handle a proxy connection failure
# begin
# Wreq.get(
Expand Down Expand Up @@ -182,6 +200,11 @@ class TlsError < Error; end

# Raised for a request failure without a more specific error subclass.
#
# Connection reset and timeout causes use their corresponding subclasses
# first. A reset takes precedence if both predicates are present. Other
# proxy and destination connection failures use their connection subclasses
# before this fallback.
#
# @example Rescue the native fallback request category
# client = Wreq::Client.new
# begin
Expand Down Expand Up @@ -218,6 +241,11 @@ class RedirectError < Error; end

# Raised when a request operation exceeds its timeout.
#
# This includes destination and proxy connection timeouts when the native
# error reports them as timeouts. Check `connection?` or `proxy_connection?`
# to see whether the native error also identifies that phase. `request?`
# can be true on the same error.
#
# @example Handle a request timeout
# client = Wreq::Client.new(timeout: 1)
# begin
Expand Down
Loading