Enforcing a global rate limit.
This commit is contained in:
@@ -61,3 +61,8 @@ func (app *application) editConflictResponse(w http.ResponseWriter, r *http.Requ
|
|||||||
message := "unable to update the record due to an edit conflict, please try again"
|
message := "unable to update the record due to an edit conflict, please try again"
|
||||||
app.errorResponse(w, r, http.StatusConflict, message)
|
app.errorResponse(w, r, http.StatusConflict, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *application) rateLimitExceededResponse(w http.ResponseWriter, r *http.Request) {
|
||||||
|
message := "rate limit exceeded"
|
||||||
|
app.errorResponse(w, r, http.StatusTooManyRequests, message)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/time/rate"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,3 +23,19 @@ func (app *application) recoverPanic(next http.Handler) http.Handler {
|
|||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (app *application) rateLimit(next http.Handler) http.Handler {
|
||||||
|
// Initialize a new rate limiter which allows an overage of 2 requests per second, with a maximum of 4 requests in a single `burst`
|
||||||
|
limiter := rate.NewLimiter(2, 4)
|
||||||
|
|
||||||
|
// The function we are returning is a closure, which 'closes over' the limiter variable
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Call limiter.Allow() to see if the request is permitted, and if it's not, then we call the rateLimitExceededResponse() helper to return a 429 Too Many Requests response (we will create this helper in a minute).
|
||||||
|
if !limiter.Allow() {
|
||||||
|
app.rateLimitExceededResponse(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,5 +31,6 @@ func (app *application) routes() http.Handler {
|
|||||||
|
|
||||||
// Return the httprouter instance.
|
// Return the httprouter instance.
|
||||||
// Wrap the router with the panic recovery middleware
|
// Wrap the router with the panic recovery middleware
|
||||||
return app.recoverPanic(router)
|
// Wrap the router with the rateLimit() middleware
|
||||||
|
return app.recoverPanic(app.rateLimit(router))
|
||||||
}
|
}
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -5,4 +5,5 @@ go 1.25.1
|
|||||||
require (
|
require (
|
||||||
github.com/julienschmidt/httprouter v1.3.0 // indirect
|
github.com/julienschmidt/httprouter v1.3.0 // indirect
|
||||||
github.com/lib/pq v1.10.9 // indirect
|
github.com/lib/pq v1.10.9 // indirect
|
||||||
|
golang.org/x/time v0.14.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -2,3 +2,5 @@ github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4d
|
|||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
|
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||||
|
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||||
|
|||||||
Reference in New Issue
Block a user