For this example, i use https://github.com/didip/tollbooth
-
Create
rate_limit.go
insidemiddlewares
folder (you can create when folder not exists) -
Copas placeholder code
package middlewares
import (
"net/http"
)
type RateLimit struct {
}
func (r *RateLimit) Attach(request *http.Request, response http.ResponseWriter) bool {
}
func (r *RateLimit) Priority() int {
return 0
}
- Look up to the handler function
From readme, we know when we want to use https://github.com/didip/tollbooth
, we just add one line like below
tollbooth.LimitFuncHandler(tollbooth.NewLimiter(1, nil), HelloHandler)
See inside tollbooth.LimitFuncHandler()
and here the code
middle := func(w http.ResponseWriter, r *http.Request) {
httpError := LimitByRequest(lmt, w, r)
if httpError != nil {
lmt.ExecOnLimitReached(w, r)
if lmt.GetOverrideDefaultResponseWriter() {
return
}
w.Header().Add("Content-Type", lmt.GetMessageContentType())
w.WriteHeader(httpError.StatusCode)
w.Write([]byte(httpError.Message))
return
}
// There's no rate-limit error, serve the next handler.
next.ServeHTTP(w, r)
}
return http.HandlerFunc(middle)
- Find
func(w http.ResponseWriter, r *http.Request)
function and copas the body to your middleware, like below (i change variable names)
limiter := tollbooth.NewLimiter(1, nil)
httpError := tollbooth.LimitByRequest(limiter, response, request)
if httpError != nil {
limiter.ExecOnLimitReached(response, request)
if limiter.GetOverrideDefaultResponseWriter() {
return true
}
response.Header().Add("Content-Type", limiter.GetMessageContentType())
response.WriteHeader(httpError.StatusCode)
response.Write([]byte(httpError.Message))
return true
}
return false
Here full code
package middlewares
import (
"net/http"
"github.com/didip/tollbooth/v6"
)
type RateLimit struct {
}
func (r *RateLimit) Attach(request *http.Request, response http.ResponseWriter) bool {
limiter := tollbooth.NewLimiter(1, nil)
httpError := tollbooth.LimitByRequest(limiter, response, request)
if httpError != nil {
limiter.ExecOnLimitReached(response, request)
if limiter.GetOverrideDefaultResponseWriter() {
return true
}
response.Header().Add("Content-Type", limiter.GetMessageContentType())
response.WriteHeader(httpError.StatusCode)
response.Write([]byte(httpError.Message))
return true
}
return false
}
func (r *RateLimit) Priority() int {
return 0
}
- Add definition to
dics/container.go
{
Name: "bima:middleware:rate-limiter",
Scope: bima.Application,
Build: (*middlewares.RateLimit)(nil),
},
- Add to
configs/middlewares.yaml
middlewares:
- rate-limiter
- Add
max
value optional
type RateLimit struct {
Max float64
}
func (r *RateLimit) Attach(request *http.Request, response http.ResponseWriter) bool {
limiter := tollbooth.NewLimiter(r.Max, nil)
httpError := tollbooth.LimitByRequest(limiter, response, request)
if httpError != nil {
limiter.ExecOnLimitReached(response, request)
if limiter.GetOverrideDefaultResponseWriter() {
return true
}
response.Header().Add("Content-Type", limiter.GetMessageContentType())
response.WriteHeader(httpError.StatusCode)
response.Write([]byte(httpError.Message))
return true
}
return false
}
- Change definition
{
Name: "bima:middleware:rate-limiter",
Scope: bima.Application,
Build: (*middlewares.RateLimit)(nil),
Params: dingo.Params{
"Max": float64(1),
},
},