linodego icon indicating copy to clipboard operation
linodego copied to clipboard

[Feature]: Helper functions for working with errors

Open nesv opened this issue 1 year ago • 0 comments

Description

While working with the Linode API, I found myself repeating a pattern for checking which specific error was returned from a failed API request.

The pattern is roughly the following:

  • Call a method on linodego.Client;
  • Unwrap the error to a *linodego.Error with errors.As;
  • If the unwrapping is successful, and has an expected error code, handle it.
client := linodego.NewClient(http.DefaultClient)

var lerr *linodego.Error
if err := client.DeleteObjectStorageKey(context.Background(), 12345); errors.As(err, &lerr) && lerr.StatusCode() == http.StatusNotFound {
    // Handle the expected error.
} else if err != nil {
    // I have an unexpected error, this is usually a simple...
    return fmt.Errorf("delete object storage key: %w", err)
}

Performing a simple if err != nil does not work in all situations, since I may want to "successfully fail" past (in this case) the DeleteObjectStorageKey request returning a 404 Not Found response.

Proposal

Addition of two, new functions to the module:

  • ErrHasStatus(err error, codes ...int) bool — uses errors.As to try and unwrap err to a *linodego.Error, before checking to see if linodego.Error.StatusCode matches any of the provided codes.
  • IsNotFound(err error) bool — a thin wrapper over ErrHasStatusCodes(err, http.StatusNotFound) for checking if the error returned from an API call is a 404 Not Found, but providing a convenience for (what in my experience has been) a common use-case. However, if this isn't considered a valuable or useful addition, that's totally okay. :smile:

Example Code

IsNotFound

client := linodego.NewClient(http.DefaultClient)
if err := client.DeleteObjectStorageKey(context.Background(), 12345); linodego.IsNotFound(err) {
    // I am expecting this, but I have more stuff to do further down.
} else if err != nil {
    // handle the unexpected error accordingly
}

ErrHasStatus

client := linodego.NewClient(http.DefaultClient)
instance, err := client.GetInstance(context.Background(), 123456)
if linodego.ErrHasStatus(err, http.StatusUnauthorized) {
    // oops, forgot my wallet at home
} else if linodego.ErrHasStatus(err, http.StatusTooManyRequests) {
    // cool my jets
} else if err != nil {
    // welp, didn't expect this...
}

nesv avatar Mar 01 '24 21:03 nesv