Exception: X::HTTPError
- Includes:
- RequestContext, ResponseHeaders
- Defined in:
- x-core/lib/x/core/errors/http_error.rb
Overview
Base class for HTTP errors from the X API
The message is what the API said went wrong, read from the body of the response, behind the method and path of the request it answered. #body holds that body as it arrived, #headers the headers it came with, and #problem the problem it describes the failure with as a whole, and #problems each problem it names, for code that acts on the reason rather than logging it. #http_method and #uri are the request the API refused.
A 4xx raises a ClientError, a 5xx a ServerError, and a body that is not JSON an InvalidResponse, each a subclass of this. It is raised itself for a redirect the client does not follow: a 300 Multiple Choices, 304 Not Modified, or 305 Use Proxy, and a redirect whose Location is missing, is not a valid URL, or is not an HTTP or HTTPS URL.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#http_response ⇒ Net::HTTPResponse
readonly
The response itself, as the client received it.
-
#problem ⇒ Problem?
readonly
The problem the API described the failure with as a whole.
-
#problems ⇒ Array<Problem>
readonly
The problems the API named in the body of the response.
Instance Method Summary collapse
-
#body ⇒ String?
The body of the response, as it arrived.
-
#headers ⇒ Hash{String => String}
The headers of the response.
-
#http_method ⇒ Symbol?
The HTTP method the request was sent with.
-
#initialize(message = nil, http_response: nil, status: nil, headers: nil, body: nil, http_method: nil, uri: nil) ⇒ HTTPError
constructor
Initialize a new HTTPError.
-
#retry_after ⇒ Integer?
The seconds the response asks a request to wait before it is sent again.
-
#status ⇒ Integer
The HTTP status code, as an Integer like X::Response#status.
-
#uri ⇒ URI::Generic?
The URI the request was sent to.
Constructor Details
#initialize(message = nil, http_response: nil, status: nil, headers: nil, body: nil, http_method: nil, uri: nil) ⇒ HTTPError
Initialize a new HTTPError
Public, so that code that rescues an HTTPError, or a subclass such as NotFound, can be tested with one built from the status, headers, and body of a response, or from a Net::HTTP response, as x-core builds each from the response it parses. The error names the request, when given its method and URI, as x-core names the request the response answers.
It can be raised as any other exception is, as in raise X::NotFound, or raise X::NotFound, "gone", for a test double that stands in for a client: an error of a status, such as NotFound, given neither a response nor a status, is built with the status x-core raises it for, a ClientError or ServerError with the first of its kind, 400 or 500, and an InvalidResponse with 200. An HTTPError itself, which is raised for a status of any kind, must be given one. A message given is the message of the error, in place of the one read from the body.
140 141 142 143 144 145 146 147 148 149 |
# File 'x-core/lib/x/core/errors/http_error.rb', line 140 def initialize( = nil, http_response: nil, status: nil, headers: nil, body: nil, http_method: nil, uri: nil) @http_response = built_response(http_response, status:, headers:, body:) name_request(http_method, uri) parsed = parsed_body errors = Problem.all_from(parsed) described = (Problem.new(parsed) if describes_problem?(parsed)) @problems = errors.empty? ? [described].compact.freeze : errors @problem = described || errors.first super(( || (parsed) || @http_response.)) end |
Instance Attribute Details
#http_response ⇒ Net::HTTPResponse (readonly)
The response itself, as the client received it
It is an escape hatch, for what the error does not read: the status is #status, the headers are #headers, and the body is #body. It is the Net::HTTP response the client sent the request with, or the one built of the status, headers, and body the error was given.
77 78 79 |
# File 'x-core/lib/x/core/errors/http_error.rb', line 77 def http_response @http_response end |
#problem ⇒ Problem? (readonly)
The problem the API described the failure with as a whole
It is the problem the body of the response describes itself, by its title, detail, type, and status, whether or not the body names errors of its own, which are #problems, so its type reads the kind of failure alike for a request the API refused a parameter of and for one it refused to authorize; its attributes are the whole body. A body that describes no problem of its own, but names errors, as the responses of v1.1 do, is described by the first of them.
104 105 106 |
# File 'x-core/lib/x/core/errors/http_error.rb', line 104 def problem @problem end |
#problems ⇒ Array<Problem> (readonly)
The problems the API named in the body of the response
They are the errors the body names, such as each parameter of the request the API refused, or else the problem the body describes itself, which is #problem.
88 89 90 |
# File 'x-core/lib/x/core/errors/http_error.rb', line 88 def problems @problems end |
Instance Method Details
#body ⇒ String?
The body of the response, as it arrived
A server can send any body with an error, so it is the JSON the API describes a failure with, or whatever else was sent in its place, such as the page of a proxy. It is tagged UTF-8, the encoding of the JSON the API sends, and a body that is not valid UTF-8 keeps its bytes, so valid_encoding? tells it apart.
188 |
# File 'x-core/lib/x/core/errors/http_error.rb', line 188 def body = http_response.body |
#headers ⇒ Hash{String => String}
The headers of the response
The names are lowercase, and a field the API sent more than once is joined with a comma.
|
|
# File 'x-core/lib/x/core/errors/http_error.rb', line 29
|
#http_method ⇒ Symbol?
The HTTP method the request was sent with
|
|
# File 'x-core/lib/x/core/errors/http_error.rb', line 29
|
#retry_after ⇒ Integer?
The seconds the response asks a request to wait before it is sent again
The API sends a Retry-After header with a request it refused for a rate limit, and with some of the responses of a failure of its own, such as a 503 that names the time its endpoint is expected back. The header counts the seconds from when the response was sent, or names the time to wait until. A client waits it out before it sends an idempotent request again, up to a minute; see Client#initialize.
201 202 203 204 205 206 |
# File 'x-core/lib/x/core/errors/http_error.rb', line 201 def retry_after value = http_response[RETRY_AFTER_HEADER] return if value.nil? value.match?(RETRY_AFTER_SECONDS) ? Integer(value, 10) : seconds_until(value) end |
#status ⇒ Integer
The HTTP status code, as an Integer like X::Response#status
176 |
# File 'x-core/lib/x/core/errors/http_error.rb', line 176 def status = Integer(http_response.code) |
#uri ⇒ URI::Generic?
The URI the request was sent to
|
|
# File 'x-core/lib/x/core/errors/http_error.rb', line 29
|