Skip to content

Noblefel/perisai

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A very basic and naive in-memory rate limiter middleware. Compatible with standard library (i think?) as it uses http.Handler interface

THIS IS NAIVE & NOT RECOMMENDED 😁

go get github.com/Noblefel/perisai

Example #1 - limit by user id:

func main() {
	mux := http.NewServeMux()

	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("ping"))
	})

	http.ListenAndServe("localhost:8080", auth(mux))
}

// example as outer variable to be grouped inside other middleware,
// OR you could just set it locally and manually assign this to each route
var limiter = perisai.New(10, 8*time.Second, perisai.FuncUserId)

// example a typical authentication middleware
func auth(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		tokenString := r.Header.Get("Authorization")

		userId, err := verifyToken(tokenString)
		if err != nil {
			w.WriteHeader(http.StatusUnauthorized)
			return
		}

		ctx := context.WithValue(r.Context(), "user_id", userId) // <--
		limiter.Handle(next).ServeHTTP(w, r.WithContext(ctx))    // <--
	})
}

func verifyToken(string) (int, error) { return 1, nil }

Example #2 - limit by ip:

var throttle = perisai.New(40, 5*time.Second, perisai.FuncIP)

Example #3 - custom value func

scenario: limit post request once every 10s. since method "post" will be too common to be incremented, we'll concat it with user id so it wont affect others.

var postLimiter = perisai.New(1, 10*time.Second, func(r *http.Request) any {
	if r.Method != "POST" {
		return nil // ignore other methods
	}
	if id := r.Context().Value("user_id"); id != nil {
		return fmt.Sprintf("%d:post", id)
	}
	return nil
})

About

A very basic and naive rate limiter middleware. Not recommended

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages