httprate icon indicating copy to clipboard operation
httprate copied to clipboard

Rate limit only on failed requests.

Open chance-schultz opened this issue 1 year ago • 3 comments

Is there an easy way to use the existing httprate functionality but push it to the end resolution of the request/response chain instead of at the beginning.

We want to create a couple of open ended mutation endpoints that could be used maliciously so we want to limit the total number of bad requests in a short period of time, but not limit penalize a user who is submitted good data that returns 2XX responses.

chance-schultz avatar Apr 08 '24 18:04 chance-schultz

Hi @chance-schultz,

This is an interesting feature request!

The current httprate pkg does rate-limiting only at the beginning of the request, which makes sense.

However I can imagine you could write a custom middleware that manipulates the limits after the handler is run and HTTP status is known.

Pseudo-code (not tested / might not compile):

rateLimiter := httprate.NewRateLimiter(1000, time.Minute, httprate.WithKeyFuncs(httprate.KeyByIP))

r := chi.NewRouter()

r.Use(rateLimiter.Handler)

r.Use(func(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
		next.ServeHTTP(ww, r)
		
		if ww.Status() >= 200 && ww.Status < 400 {
			key := httprate.KeyByRealIP(r)
			currentWindow := time.Now().UTC().Truncate(time.Minute)
			rateLimiter.Counter().IncrementBy(key, currentWindow, -1) // Put back 
		}
	})
})

VojtechVitek avatar Jul 24 '24 13:07 VojtechVitek