requests icon indicating copy to clipboard operation
requests copied to clipboard

feat: add ability to register error handler callback

Open nicjohnson145 opened this issue 3 years ago • 3 comments

nicjohnson145 avatar Sep 15 '22 21:09 nicjohnson145

Oh, also Clone needs to be updated if you use a map.

earthboundkid avatar Sep 15 '22 23:09 earthboundkid

so it might as well be a struct

as in a dedicated struct for this

type ErrorHandlers struct {
    OnAnyErr ErrorHandler
    OnConnectionErr ErrorHandler
    ...
}

with the OnError method expanded to just take the struct directly? i.e

func (rb *Builder) OnError(handlers ErrorHandlers) *Builder {
   rb.errorHandlers = handlers
   return rb
}

Or would you still want to keep the enum around?

As for testing out how it feels to use, I've actually got a perfect project at work in mind for it. It was actually the reason I proposed the change in the first place 😅. FWIW, using it during the tests was fine, I think I would have preferred a OnValidationError, OnConnectionError, etc methods but I'm pretty sure that's just personal taste. I think whichever mechanism (struct vs enum) is used, the way the "any" variant interacts with the more specific variants should be solidified and add into the doc comment. I'm stuck between the specific error kind is checked first with any as a fallback, and any supersedes all.

nicjohnson145 avatar Sep 15 '22 23:09 nicjohnson145

Can't link you to the code (because private repo) but the redacted gist of the change with this new behavior is

log.Trace("Project ID not found, creating")
var resp createProjectResponse
b := requests.
	URL("https://gitlab.com/api/v4/projects").
	BodyJSON(&data).
	Header("PRIVATE-TOKEN", pat).
	ToJSON(&resp)
b = bodyLoggingOnError(b)
err = b.Fetch(context.TODO())
if err != nil {
	return 0, "", fmt.Errorf("error creating project: %w", err)
}

to

log.Trace("Project ID not found, creating")
var resp createProjectResponse
err := requests.
	URL("https://gitlab.com/api/v4/projects").
	BodyJSON(&data).
	Header("PRIVATE-TOKEN", pat).
	OnError(requests.ErrorKindValidationErr, func(kind requests.ErrorKind, cause error, resp *http.Response) error {
		body, err := io.ReadAll(resp.Body)
		if err != nil {
			return fmt.Errorf("during handling %v: error reading response body: %v", cause, err)
		}
		log.Error(body)
		return cause
	}).
	ToJSON(&resp).
	Fetch(context.TODO())
if err != nil {
	return 0, "", fmt.Errorf("error creating project: %w", err)
}

where bodyLoggingOnError was doing the "custom validator that just called the default validator and did error logging" bits

nicjohnson145 avatar Sep 16 '22 16:09 nicjohnson145

+1 to this, personally I'd like to try the request, then if I get a 401 then I need to refresh the access token (which should be handled by some other function).

OscarVanL avatar Dec 14 '22 19:12 OscarVanL

@OscarVanL Please try out #54 which has this functionality. It's currently available as v0.22.4-alpha3.

earthboundkid avatar Dec 14 '22 20:12 earthboundkid

In the specific case of an oauth refresh token, I think you can and should do it as a custom transport.

earthboundkid avatar Dec 14 '22 20:12 earthboundkid

Thanks for this suggestion!

OscarVanL avatar Dec 14 '22 22:12 OscarVanL

I'm closing this because what I really need feedback on is #54.

earthboundkid avatar Dec 15 '22 02:12 earthboundkid