Handling of error responses from Katapult's API isn't great right now, as we
don't actually parse the detail attribute due to the type being different
depending on the type of error.
To address this, we need to create a whole series of error structs that match up
against all of the error types the Katapult API can return, which are capable of
parsing the detail
property according to the the type of that error. These
errors should also conform to the error
interface, where the Error()
method
returns a sensible string version of itself, taking code
, description
, and
detail
values into account. These custom error structs should also implement
Unwrap()
and Is()
methods, and act as if they've wrapped a standard error
var.
The existing ResponseError
structs will then be used to initially parse the
returned JSON response, and based on the Code
field, we initialize the
relevant error struct, having it parse the Detail json.RawMessage
field.
All API methods which currently return a stuct, Response
, and error
should
then be changed, so the error
is actually the parsed error struct.
As an example, right now if you get a error back, but want custom logic if it is
a 404 not found error, something like this must be done:
ip, resp, err := client.IPAddresses.GetByID(ctx, "ip_r3NoJOsbEtZOwT89")
if err != nil {
if resp != nil && resp.Response && resp.StatusCode != 404 {
// do something for not found errors
} else {
// do something for any other error
}
}
The above is rather cumbersome and annoying, instead I would like to be able to
do something like this:
ip, resp, err := client.IPAddresses.GetByID(ctx, "ip_r3NoJOsbEtZOwT89")
if err != nil {
if errors.Is(err, katapult.ErrNotFound) {
// do something for not found errors
} else {
// do something for any other error
}
}
Errors should also have a multiple levels of wrapping, so in the above example,
err
is all of the following when checked with errors.Is()
:
katapult.ErrIPAddressNotFound
katapult.ErrNotFound
katapult.Err
As a final note, once errors are actually returned as the error
return value,
the Response
return value should probably be refactored into some form of
"meta" object, as it'll mostly just be needed for pagination details, rate
limits, and other such "meta" about the response.