'Rate limit with golang.org/x/time/rate api request

I already created a function for limiting to 50 requests for API logins in one day.

var limit = 50

package middleware

import (
    "log"
    "net"
    "net/http"
    "sync"
    "time"

    "golang.org/x/time/rate"
)

// Create a custom request struct which holds the rate limiter for each
// visitor and the last time that the request was seen.
type request struct {
    limiter  *rate.Limiter
    lastSeen time.Time
}

// Change the the map to hold values of the type request.
// defaultTime using 3 minutes
var requests = make(map[string]*request)
var mu sync.Mutex

func getRequest(ip string, limit int) *rate.Limiter {
    mu.Lock()
    defer mu.Unlock()

    v, exists := requests[ip]
    if !exists {
        limiter := rate.NewLimiter(1, limit)
        requests[ip] = &request{limiter, time.Now()}
        return limiter
    }
    // Update the last seen time for the visitor.
    v.lastSeen = time.Now()
    return v.limiter
}

func throttle(next http.Handler, limit int) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ip, _, err := net.SplitHostPort(r.RemoteAddr)
        if err != nil {
            log.Println(err.Error())
            http.Error(w, "Internal Server Error", http.StatusInternalServerError)
            return
        }
        limiter := getRequest(ip, limit)
        fmt.Println(limiter.Allow())
        if limiter.Allow() == false {
            http.Error(w, http.StatusText(http.StatusTooManyRequests), http.StatusTooManyRequests)
            return
        }
        next.ServeHTTP(w, r)
    })
}

Is it correct?

Because when I try it, it still passes. The function limit is not working.

I doubt with NewLimiter()

 limiter := rate.NewLimiter(1, limit)

Does it mean one user only can request login 50 requests per day? (I already read the docs, but I do not understand.)



Solution 1:[1]

From the rate docs:

func NewLimiter(r Limit, b int) *Limiter

NewLimiter returns a new Limiter that allows events up to rate r and permits bursts of at most b tokens.


So the first parameter is the rate-limit, not the second. Burst is the number of requests you want to allow that occur faster than the rate-limit - typically one uses a value of 1 to disallow bursting, anything higher will let this number of requests in before the regular rate-limit kicks in. Anyway...

To create the rate.Limit for your needs, you can use the helper function rate.Every():

rt := rate.Every(24*time.Hour / 50)

limiter := rate.NewLimiter(rt, 1)

Solution 2:[2]

NewLimited(1, 50) means 1 request/second with a burst of up to 50 requests. It's a token bucket, which means that there are 50 tokens, each accepted API call uses up one token, and the tokens are regenerated at the given rate, up to burst. Your code is creating a limiter per IP address, so that's a limit per IP address (which I guess you are approximating as one IP address is one user).

If you're running on a single persistent server, and the server and code never restarts, then you may be able to get something like 50 requests/day per user by specifying a rate of 50 / (3600*24) and a burst of 50. (Note: 3600*24 is the number of seconds in a day). But the rate limiting package you're using is not designed for such coarse rate-limiting (on the order of requests per day) -- it's designed to prevent server overload under heavy traffic in the short term (on the order of requests per second).

You probably want a rate-limiter that works with a database or similar (perhaps using a token bucket scheme, since that can be implemented efficiently). Probably there's a package somewhere for that, but I don't know of one of the top of my head.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 colm.anseo
Solution 2 Peter Mortensen