Dead simple rate limit middleware for Go.

Limiter

Documentation License Build Status Go Report Card

Dead simple rate limit middleware for Go.

  • Simple API
  • "Store" approach for backend
  • Redis support (but not tied too)
  • Middlewares: HTTP, FastHTTP and Gin

Installation

Using Go Modules

$ go get github.com/ulule/limiter/[email protected]

Usage

In five steps:

  • Create a limiter.Rate instance (the number of requests per period)
  • Create a limiter.Store instance (see Redis or In-Memory)
  • Create a limiter.Limiter instance that takes store and rate instances as arguments
  • Create a middleware instance using the middleware of your choice
  • Give the limiter instance to your middleware initializer

Example:

// Create a rate with the given limit (number of requests) for the given
// period (a time.Duration of your choice).
import "github.com/ulule/limiter/v3"

rate := limiter.Rate{
    Period: 1 * time.Hour,
    Limit:  1000,
}

// You can also use the simplified format "<limit>-<period>"", with the given
// periods:
//
// * "S": second
// * "M": minute
// * "H": hour
// * "D": day
//
// Examples:
//
// * 5 reqs/second: "5-S"
// * 10 reqs/minute: "10-M"
// * 1000 reqs/hour: "1000-H"
// * 2000 reqs/day: "2000-D"
//
rate, err := limiter.NewRateFromFormatted("1000-H")
if err != nil {
    panic(err)
}

// Then, create a store. Here, we use the bundled Redis store. Any store
// compliant to limiter.Store interface will do the job. The defaults are
// "limiter" as Redis key prefix and a maximum of 3 retries for the key under
// race condition.
import "github.com/ulule/limiter/v3/drivers/store/redis"

store, err := redis.NewStore(client)
if err != nil {
    panic(err)
}

// Alternatively, you can pass options to the store with the "WithOptions"
// function. For example, for Redis store:
import "github.com/ulule/limiter/v3/drivers/store/redis"

store, err := redis.NewStoreWithOptions(pool, limiter.StoreOptions{
    Prefix:   "your_own_prefix",
})
if err != nil {
    panic(err)
}

// Or use a in-memory store with a goroutine which clears expired keys.
import "github.com/ulule/limiter/v3/drivers/store/memory"

store := memory.NewStore()

// Then, create the limiter instance which takes the store and the rate as arguments.
// Now, you can give this instance to any supported middleware.
instance := limiter.New(store, rate)

// Alternatively, you can pass options to the limiter instance with several options.
instance := limiter.New(store, rate, limiter.WithTrustForwardHeader(true), limiter.WithIPv6Mask(mask))

// Finally, give the limiter instance to your middleware initializer.
import "github.com/ulule/limiter/v3/drivers/middleware/stdlib"

middleware := stdlib.NewMiddleware(instance)

See middleware examples:

How it works

The ip address of the request is used as a key in the store.

If the key does not exist in the store we set a default value with an expiration period.

You will find two stores:

  • Redis: rely on TTL and incrementing the rate limit on each request.
  • In-Memory: rely on a fork of go-cache with a goroutine to clear expired keys using a default interval.

When the limit is reached, a 429 HTTP status code is sent.

Why Yet Another Package

You could ask us: why yet another rate limit package?

Because existing packages did not suit our needs.

We tried a lot of alternatives:

  1. Throttled. This package uses the generic cell-rate algorithm. To cite the documentation: "The algorithm has been slightly modified from its usual form to support limiting with an additional quantity parameter, such as for limiting the number of bytes uploaded". It is brillant in term of algorithm but documentation is quite unclear at the moment, we don't need burst feature for now, impossible to get a correct After-Retry (when limit exceeds, we can still make a few requests, because of the max burst) and it only supports http.Handler middleware (we use Gin). Currently, we only need to return 429 and X-Ratelimit-* headers for n reqs/duration.

  2. Speedbump. Good package but maybe too lightweight. No Reset support, only one middleware for Gin framework and too Redis-coupled. We rather prefer to use a "store" approach.

  3. Tollbooth. Good one too but does both too much and too little. It limits by remote IP, path, methods, custom headers and basic auth usernames... but does not provide any Redis support (only in-memory) and a ready-to-go middleware that sets X-Ratelimit-* headers. tollbooth.LimitByRequest(limiter, r) only returns an HTTP code.

  4. ratelimit. Probably the closer to our needs but, once again, too lightweight, no middleware available and not active (last commit was in August 2014). Some parts of code (Redis) comes from this project. It should deserve much more love.

There are other many packages on GitHub but most are either too lightweight, too old (only support old Go versions) or unmaintained. So that's why we decided to create yet another one.

Contributing

Don't hesitate ;)

Comments
  • Improve the performance of the Redis store with Lua script

    Improve the performance of the Redis store with Lua script

    the performance of the Limiter Get with Redis transaction:

    BenchmarkGet-8   	    3110	    360345 ns/op
    
    

    the performance of the Limiter Get with Redis Lua script:

    BenchmarkGet-8   	    9850	    120478 ns/op
    

    it shows that Lua script would be 3x faster, the benchmark case was added in store_test.go

  • V3 with dep

    V3 with dep

    How can I use this package if I'm using dep rather than modules?

    When I run dep ensure I get these errors:

    Solving failure: No versions of github.com/ulule/limiter met constraints:
    	v3.1.0: Could not introduce github.com/ulule/[email protected], as its subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	v3.0.0: Could not introduce github.com/ulule/[email protected], as its subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	v2.2.2: Could not introduce github.com/ulule/[email protected], as its subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	v2.2.1: Could not introduce github.com/ulule/[email protected], as its subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	v2.2.0: Could not introduce github.com/ulule/[email protected], as its subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	v2.1.0: Could not introduce github.com/ulule/[email protected], as its subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	v2.0.0: Could not introduce github.com/ulule/[email protected], as its subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	v1.0.0: Could not introduce github.com/ulule/[email protected] due to multiple problematic subpackages:
    	Subpackage github.com/ulule/limiter/drivers/middleware/stdlib is missing. (Package is required by (root).)	Subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	master: Could not introduce github.com/ulule/limiter@master, as its subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	dev: Could not introduce github.com/ulule/limiter@dev, as its subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	v1: Could not introduce github.com/ulule/limiter@v1 due to multiple problematic subpackages:
    	Subpackage github.com/ulule/limiter/drivers/middleware/stdlib is missing. (Package is required by (root).)	Subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    	v2: Could not introduce github.com/ulule/limiter@v2, as its subpackage github.com/ulule/limiter/v3/drivers/store/redis is missing. (Package is required by (root).)
    
  • Memory store clean command is a blocker

    Memory store clean command is a blocker

    Limiter is running on a high traffic server so while debugging some problems I saw high letancy from the store cleaner. I know that we need to remove the expired records but maybe there is a better way to do it?

    Screenshot 2020-03-27 at 8 07 56 PM

  • GetIP TrustForwardHeader varies per request

    GetIP TrustForwardHeader varies per request

    The recent change in https://github.com/ulule/limiter/blob/4499266ea10ad0d8b50b9fbf60a060cc95a96870/network.go#L17-L39 conflicts with the nature of the limiter. Since the limiter object is instantiated early before the server stats and then shared among different requests whose IPs are different. IMHO the TrustForwardHeader should vary based on how much the server trusts the IP and should not be as a config rule.

    Also the change of GetIP is not backward compatible - AKA broke my build :)

    The old signature used to be

    func GetIP(r *http.Request, trustForwardHeader bool) net.IP 
    
  • rate limiting by IP address prefix

    rate limiting by IP address prefix

    For IPv6, it doesn't make sense to rate limit individual /128 addresses since end hosts often get a huge prefix assigned to them, making it easy to bypass rate limits. Instead, how about adding a normalization prefix (default /32 for IPv4 and /128 IPv6 to keep existing functionality)?

    It can be trivially accomplished by masking the desired number of bits for the prefix and using that as the IP key, for example:

    IPv4: 192.0.2.123 with a /24 prefix: becomes192.0.2.0 IPv6: 2001:db8:cafe:1234:beef::fafa with /48 prefix becomes 2001:db8:cafe::

  • package limiter/drivers/store/common includes test flags in main binary

    package limiter/drivers/store/common includes test flags in main binary

    I'm currently using "limiter/drivers/store/memory" cache independently from also using the Limiter. It seems that because there is a "limiter/drivers/store/common/tests.go" in the common package, the testing package injects its flags into my application.

    Could this tests.go file be renamed to "common_test.go"?

  • Add an option to customize the rate limiter key in gin middleware

    Add an option to customize the rate limiter key in gin middleware

    The user of the library can set the way the rate limiter key is computed by passing a function taking the gin context as input. We keep the current behavior by default by providing a function returning the Client IP address as a default key getter.

  • Concurrency issues in memory store

    Concurrency issues in memory store

    Noticed when reviewing the code in store_memory.go that it retrieved the cache item checked if it expired and then attempted to increment it but there was no mutex or anything to protect that.

    So it's possible that we check that it hasn't expired but by the time we IncrementInt64 it has expired and is not in the cache resulting in an error:

    item, found := s.Cache.Items()[key]
        ms := int64(time.Millisecond)
        now := time.Now()
    
           // ** TIME A: HAS NOT EXPIRED YET
        if !found || item.Expired() {
            s.Cache.Set(key, int64(1), rate.Period)
    
            return Context{
                Limit:     rate.Limit,
                Remaining: rate.Limit - 1,
                Reset:     (now.UnixNano()/ms + int64(rate.Period)/ms) / 1000,
                Reached:   false,
            }, nil
        }
    
            // ** TIME B: key has expired so this will return an error
        count, err := s.Cache.IncrementInt64(key, 1)
        if err != nil {
            return ctx, err
        }
    

    This is a little bit of an edge case, but it does result in unexpected behavior in a high concurrency environment.

    Here's a unit test spawning a bunch of goroutines resulting in an error:

    • https://github.com/dougnukem/limiter/tree/concurrency_issue
    func TestConcurrency(t *testing.T) {
        rate := Rate{Period: time.Nanosecond * 10, Limit: 100000}
    
        store := NewMemoryStoreWithOptions(StoreOptions{
            Prefix:          "limitertests:memory",
            CleanUpInterval: 1 * time.Nanosecond,
        })
    
        wg := sync.WaitGroup{}
        limiter := NewLimiter(store, rate)
        for i := 0; i < 1000; i++ {
            wg.Add(1)
            go func(i int) {
                for j := 0; j < 10000; j++ {
                    _, err := limiter.Get("boo2")
                    assert.NoError(t, err)
                }
                wg.Done()
            }(i)
        }
        wg.Wait()
    }
    
            Error Trace:    2:
        Error:      No error is expected but got Item limitertests:memory:boo2 not found
    
            Error Trace:    2:
        Error:      No error is expected but got Item limitertests:memory:boo2 not found
    
  • setRate function refresh the key expire time when the key exist?

    setRate function refresh the key expire time when the key exist?

    hi, i have a question, this function below in store_redis.go

      func (s RedisStore) setRate(c redis.Conn, key string, rate Rate) ([]int, error) {
            c.Send("MULTI")
            c.Send("SETNX", key, 1)
            c.Send("EXPIRE", key, rate.Period.Seconds())
            return redis.Ints(c.Do("EXEC"))
     }
    

    if the key exist in redis, the function will refresh the expire time of the key, it's design so or bug?

  • Should be flexible enough to support advanced use-cases

    Should be flexible enough to support advanced use-cases

    We were considering this library to be used for advanced use-cases such as limiting requests based on Graphql query complexity. I see this works great with RPS use-case but it can also support other use-cases if library consumers are allowed to pass an integer value (a variable instead of hard-coded value 1) to increment method available under drivers (redis/memory) ( Inc method ). This way it would be more flexible for user to pass any value to Redis incrby script as per their needs. I think it would be practical to add another method or api to allow this so to extend it for other use cases as well.

  • work behind load balancer

    work behind load balancer

    Hello,

    I will deploy my service behind a load balancer, means all of the request from users will send firstly to the load balancer, then the LB will forward the request to my service. In such architecture, it is said by https://aws.amazon.com/premiumsupport/knowledge-center/elb-find-load-balancer-IP/ that '''You can determine the IP addresses associated with an internal load balancer or an internet-facing load balancer by resolving the DNS name of the load balancer. These are the IP addresses where the clients should send the requests that are destined for the load balancer. However, Classic Load Balancers and Application Load Balancers use the private IP addresses associated with their elastic network interfaces as the source IP address for requests forwarded to your web servers.''' In such architecture, if the source IP of the request is the IP of the load balancer (not the IP of the end user), if ulule apply the request rate limitation, it will in fact limit the total output of the service. Should I do some configuration on ulule limiter or the on the load balancer? or ulule already support such architecture quite well?

    Thanks for your answer,

    James

  • chore(go.mod): bump github.com/gin-gonic/gin from 1.7.7 to 1.8.2

    chore(go.mod): bump github.com/gin-gonic/gin from 1.7.7 to 1.8.2

    Bumps github.com/gin-gonic/gin from 1.7.7 to 1.8.2.

    Release notes

    Sourced from github.com/gin-gonic/gin's releases.

    v1.8.2

    Changelog

    Bug fixes

    • 0c2a691 fix(engine): missing route params for CreateTestContext (#2778) (#2803)
    • e305e21 fix(route): redirectSlash bug (#3227)

    Others

    • 6a2a260 Fix the GO-2022-1144 vulnerability (#3432)

    v1.8.1

    Changelog

    Features

    • f197a8b feat(context): add ContextWithFallback feature flag (#3166) (#3172)

    v1.8.0

    Changelog

    Break Changes

    • TrustedProxies: Add default IPv6 support and refactor #2967. Please replace RemoteIP() (net.IP, bool) with RemoteIP() net.IP
    • gin.Context with fallback value from gin.Context.Request.Context() #2751

    BUGFIXES

    • Fixed SetOutput() panics on go 1.17 #2861
    • Fix: wrong when wildcard follows named param #2983
    • Fix: missing sameSite when do context.reset() #3123

    ENHANCEMENTS

    • Use Header() instead of deprecated HeaderMap #2694
    • RouterGroup.Handle regular match optimization of http method #2685
    • Add support go-json, another drop-in json replacement #2680
    • Use errors.New to replace fmt.Errorf will much better #2707
    • Use Duration.Truncate for truncating precision #2711
    • Get client IP when using Cloudflare #2723
    • Optimize code adjust #2700
    • Optimize code and reduce code cyclomatic complexity #2737
    • gin.Context with fallback value from gin.Context.Request.Context() #2751
    • Improve sliceValidateError.Error performance #2765
    • Support custom struct tag #2720
    • Improve router group tests #2787
    • Fallback Context.Deadline() Context.Done() Context.Err() to Context.Request.Context() #2769
    • Some codes optimize #2830 #2834 #2838 #2837 #2788 #2848 #2851 #2701
    • Test(route): expose performRequest func #3012
    • Support h2c with prior knowledge #1398

    ... (truncated)

    Changelog

    Sourced from github.com/gin-gonic/gin's changelog.

    Gin v1.8.2

    Bugs

    • fix(route): redirectSlash bug (#3227)
    • fix(engine): missing route params for CreateTestContext (#2778) (#2803)

    Security

    • Fix the GO-2022-1144 vulnerability (#3432)

    Gin v1.8.1

    ENHANCEMENTS

    • feat(context): add ContextWithFallback feature flag #3172

    Gin v1.8.0

    Break Changes

    • TrustedProxies: Add default IPv6 support and refactor #2967. Please replace RemoteIP() (net.IP, bool) with RemoteIP() net.IP
    • gin.Context with fallback value from gin.Context.Request.Context() #2751

    BUGFIXES

    • Fixed SetOutput() panics on go 1.17 #2861
    • Fix: wrong when wildcard follows named param #2983
    • Fix: missing sameSite when do context.reset() #3123

    ENHANCEMENTS

    • Use Header() instead of deprecated HeaderMap #2694
    • RouterGroup.Handle regular match optimization of http method #2685
    • Add support go-json, another drop-in json replacement #2680
    • Use errors.New to replace fmt.Errorf will much better #2707
    • Use Duration.Truncate for truncating precision #2711
    • Get client IP when using Cloudflare #2723
    • Optimize code adjust #2700
    • Optimize code and reduce code cyclomatic complexity #2737
    • Improve sliceValidateError.Error performance #2765
    • Support custom struct tag #2720
    • Improve router group tests #2787
    • Fallback Context.Deadline() Context.Done() Context.Err() to Context.Request.Context() #2769
    • Some codes optimize #2830 #2834 #2838 #2837 #2788 #2848 #2851 #2701
    • TrustedProxies: Add default IPv6 support and refactor #2967
    • Test(route): expose performRequest func #3012
    • Support h2c with prior knowledge #1398
    • Feat attachment filename support utf8 #3071
    • Feat: add StaticFileFS #2749

    ... (truncated)

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • chore(go.mod): bump github.com/valyala/fasthttp from 1.34.0 to 1.43.0

    chore(go.mod): bump github.com/valyala/fasthttp from 1.34.0 to 1.43.0

    Bumps github.com/valyala/fasthttp from 1.34.0 to 1.43.0.

    Release notes

    Sourced from github.com/valyala/fasthttp's releases.

    v1.43.0

    • dbf457e Revert "feat: support mulit/range (#1398)" (#1446) (Erik Dubbelboer)
    • c50de95 client.go fix addMissingPort() (#1444) (Sergey Ponomarev)

    v1.42.0

    • 4995135 feat: add ShutdownWithContext (#1383) (kinggo)
    • 7b3bf58 style: modify typo and remove repeated type conversions (#1437) (kinggo)
    • 8f43443 Wait for the response of pipelineWork in background and return it to pool (#1436) (Andy Pan)
    • c367454 Fix some potential pool leaks (#1433) (Andy Pan)
    • b32a3dd Use time.Until(deadline) instead of -time.Since(deadline) (#1434) (Andy Pan)
    • 8a60232 Assert with *net.TCPConn instead of *net.TCPListener in acceptConn() for TCP sockets (#1432) (Andy Pan)
    • c57a2ce Make sure nothing is nil in tmp slice (#1423) (hs son)
    • f095481 Request.SetTimeout (#1415) (brian-armstrong-discord)
    • c88dd5d fix form empty field error when used with pipe (#1417) (nick9822)
    • a468a7d feat: support mulit/range (#1398) (byene0923)
    • 3963a79 feat: add PeekKeys and PeekTrailerKeys (#1405) (kinggo)
    • eca86de fix: (#1410) (byene0923)
    • e214137 fix: ignore body should not set content-length of streaming (#1406) (byene0923)

    v1.41.0

    • 128e9b3 optimize: adjust the behavior of PeekAll based on VisitAll (#1403) (kinggo)
    • 2c8ce3b feat: add header.PeekAll (#1394) (kinggo)
    • d404f2d make RequestCtx's userdata accept keys that are of type: interface{} (#1387) (pj)
    • bcf7e8e test: merge test in adaptor_test.go (#1381) (kinggo)
    • 31fdc79 resolve CVE-2022-27664 (#1377) (Craig O'Donnell)
    • 40eec0b byte to string unsafe conversion in fasthttpadaptor ConvertRequest method (#1375) (Emre Savcı)
    • a696949 Deprecate Go 1.15 (#1379) (Aoang)

    v1.40.0

    • 2f1e949 Improve isTLSAlready check (Erik Dubbelboer)
    • 404c8a8 Chore (#1365) (tyltr)
    • 79ccfff Don't use tls ClientSessionCache (Erik Dubbelboer)
    • 28bec71 Fix "use of closed network connection" error check (Erik Dubbelboer)
    • 3b147b7 Fix(server): reset maxRequestBodySize to the server's config (#1360) (Geralt X Li)
    • af94725 Reduce slice growth in adaptor (#1356) (Qing Moy)

    v1.39.0

    • ea60524 Add Go 1.19 Support (#1355) (Aoang)
    • a5f448f Improve Client timeout (#1346) (Erik Dubbelboer)
    • 42f83c6 Prevent overflow and panic on large HTTP responses (#1351) (mathew)
    • f3513cc Introduce FS.CompressRoot (#1331) (mojatter)
    • c94be05 use timeout insteadof read/writetimeout when timeout lower than read/… (#1336) (fare83)
    • b23c5e9 Close new connections after 5s in closeIdleConns (Erik Dubbelboer)
    • 5b0cbf2 Fix apparent documentation typo (#1330) (kayos)

    v1.38.0

    • 16d30c4 Support AIX SO_REUSEADDR and SO_REUSEPORT (#1328) (zhangyongding)
    • bc24f9d Consolidate TCPKeepalive in server.Serve (#1320) (#1324) (Y.Horie)
    • 8a32089 Add ConnPoolStrategy field to client (#1317) (Thearas)
    • 35aca7b BodyDecoded() for request and responses (#1308) (Sergey Ponomarev)

    ... (truncated)

    Commits
    • dbf457e Revert "feat: support mulit/range (#1398)" (#1446)
    • c50de95 client.go fix addMissingPort() (#1444)
    • 4995135 feat: add ShutdownWithContext (#1383)
    • 7b3bf58 style: modify typo and remove repeated type conversions (#1437)
    • 8f43443 Wait for the response of pipelineWork in background and return it to pool (#1...
    • c367454 Fix some potential pool leaks (#1433)
    • b32a3dd Use time.Until(deadline) instead of -time.Since(deadline) (#1434)
    • 8a60232 Assert with *net.TCPConn instead of *net.TCPListener in acceptConn() for TCP ...
    • c57a2ce Make sure nothing is nil in tmp slice (#1423)
    • f095481 Request.SetTimeout (#1415)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • limit of dynamic route

    limit of dynamic route

    Hello,

    I have a post request like /route/{id}, where the id can be dynamic value like 001 or 002 or other, when I add limiter, i.e. 2-S, as middleware on the request, I want to ensure that when user post to /route/001 more than 2 times per second, they will be rejected by 429, but if he/she post to /route/001 then to /route/002 then to /route/003, even it happens in one second, they can still be accepted. Currently in my test the post to /route/003 failed by 429.

    Thanks,

    james

  • chore(go.mod): bump github.com/stretchr/testify from 1.7.0 to 1.8.1

    chore(go.mod): bump github.com/stretchr/testify from 1.7.0 to 1.8.1

    Bumps github.com/stretchr/testify from 1.7.0 to 1.8.1.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
  • Custom keys?

    Custom keys?

    Is it possible to have other keys than IP-addresses? I want to make rate limit middle-wares for both IP and other properties.

    Something like this library has where you provide a key-function to the Limiter https://github.com/JGLTechnologies/gin-rate-limit

Go http middleware handler for request coalescing

HTTP Coala NOTE: a new and improved implementation is available at https://github.com/go-chi/stampede Just a little bit of performance enhancing middl

Apr 3, 2022
Idiomatic HTTP Middleware for Golang

Negroni Notice: This is the library formerly known as github.com/codegangsta/negroni -- Github will automatically redirect requests to this repository

Dec 31, 2022
A simple blog framework built with GO. Uses HTML files and a JSON dict to give you more control over your content.

Go-Blog A simple template based blog framework. Instructions Built for GO version: 1 See the Documentation or Getting Started pages in the wiki. Notes

Sep 10, 2022
Simple HTTP and REST client library for Go

Resty Simple HTTP and REST client library for Go (inspired by Ruby rest-client) Features section describes in detail about Resty capabilities Resty Co

Jan 9, 2023
Simple web framework for go, still quite beta at this point

WFDR Framework - Beta Release New 18/Feb/2012: Updated for go 1.0, new directory layout to take advantage of the go build tool. Background There's a m

Feb 11, 2021
Simple Contributors Report For Git

git-contrib Creates simple contributors report for git. Useful for different bra

Nov 20, 2022
Dead simple rate limit middleware for Go.

Limiter Dead simple rate limit middleware for Go. Simple API "Store" approach for backend Redis support (but not tied too) Middlewares: HTTP, FastHTTP

Jan 1, 2023
Docker-hub-rate-limit - Show pulling rate status of Docker-hub

Docker-Hub Pull Rate Status This tool shows current status of docker hub pull ra

Jan 28, 2022
Pacemaker - Rate limit library. Currently implemented rate limits are

PaceMaker Rate limit library. Currently implemented rate limits are Fixed window

Nov 5, 2022
Simple middleware to rate-limit HTTP requests.

Tollbooth This is a generic middleware to rate-limit HTTP requests. NOTE 1: This library is considered finished. NOTE 2: Major version changes are bac

Jan 4, 2023
Simple middleware to rate-limit HTTP requests.

Tollbooth This is a generic middleware to rate-limit HTTP requests. NOTE 1: This library is considered finished. NOTE 2: Major version changes are bac

Dec 28, 2022
Limit-order-book - Limit order books keep records of orders for a given symbol to be traded

Limit Order Book Limit order books keep records of orders for a given symbol to

Jan 17, 2022
A Golang blocking leaky-bucket rate limit implementation

Go rate limiter This package provides a Golang implementation of the leaky-bucket rate limit algorithm. This implementation refills the bucket based o

Jan 2, 2023
Automatically create global & local Rate Limit in Istio, support EnvoyFilter versioning!

istio-ratelimit-operator Istio ratelimit operator provide an easy way to configure Global or Local Ratelimit in Istio mesh. Istio ratelimit operator a

Oct 24, 2022
Dhrate - Quickly check Dockerhub rate (limit) as an unauthenticated user
Dhrate - Quickly check Dockerhub rate (limit) as an unauthenticated user

Dockerhub Rate A small Go program that returns the Dockerhub rate of an unauthen

Feb 7, 2022
Ratelimit - This package provides a Golang implementation of the leaky-bucket rate limit algorithm

Go rate limiter This package provides a Golang implementation of the leaky-bucke

Jul 26, 2022
A very simple rate limiter in go, made as a learning project to learn go and rate limiting patterns!
A very simple rate limiter in go, made as a learning project to learn go and rate limiting patterns!

rate-limiter-go A very simple rate limiter in go, made as a learning project to learn go and rate limiting patterns! Demo: Running the project: To exe

Jun 1, 2022
A dead simple, highly performant, highly customizable sessions middleware for go http servers.

If you're interested in jwt's, see my jwt library! Sessions A dead simple, highly performant, highly customizable sessions service for go http servers

Dec 19, 2022
A concurrent rate limiter library for Golang based on Sliding-Window rate limiter algorithm.

ratelimiter A generic concurrent rate limiter library for Golang based on Sliding-window rate limitng algorithm. The implementation of rate-limiter al

Jan 6, 2023
Redis-rate-limiter - An abstraction over redist rate/v9 package

RATE_LIMIT_POC Notes This POC is based on github.com/go-redis/redis_rate/v9 pack

Feb 14, 2022