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/[email protected], 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/[email protected], 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/[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).)
    	v2: 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).)
    
  • 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/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

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

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

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

    Release notes

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

    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
    • Feat attachment filename support utf8 #3071
    • Feat: add StaticFileFS #2749
    • Feat(context): return GIN Context from Value method #2825
    • Feat: automatically SetMode to TestMode when run go test #3139
    • Add TOML bining for gin #3081
    • IPv6 add default trusted proxies #3033

    DOCS

    • Add note about nomsgpack tag to the readme #2703

    ... (truncated)

    Changelog

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

    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
    • Feat(context): return GIN Context from Value method #2825
    • Feat: automatically SetMode to TestMode when run go test #3139
    • Add TOML bining for gin #3081
    • IPv6 add default trusted proxies #3033

    DOCS

    • Add note about nomsgpack tag to the readme #2703
    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)
A dead simple parser package for Go
A dead simple parser package for Go

A dead simple parser package for Go

Nov 26, 2022
An HTTP client for go-server-timing middleware. Enables automatic timing propagation through HTTP calls between servers.

client-timing An HTTP client for go-server-timing middleware. Features: An HTTP Client or RoundTripper, fully compatible with Go's standard library. A

Dec 1, 2022
Fault injection library in Go using standard http middleware

Fault The fault package provides go http middleware that makes it easy to inject faults into your service. Use the fault package to reject incoming re

Nov 20, 2022
Go middleware for monetizing your API on a per-request basis with Bitcoin and Lightning ⚡️

ln-paywall Go middleware for monetizing your API on a per-request basis with Bitcoin and Lightning ⚡️ Middlewares for: net/http HandlerFunc net/http H

Nov 25, 2022
A Golang Middleware to handle X-Forwarded-For Header

X-Forwarded-For middleware fo Go Package xff is a net/http middleware/handler to parse Forwarded HTTP Extension in Golang. Example usage Install xff:

Nov 3, 2022
Redcon is a custom Redis server framework for Go that is fast and simple to use.
Redcon is a custom Redis server framework for Go that is fast and simple to use.

Redcon is a custom Redis server framework for Go that is fast and simple to use. The reason for this library it to give an efficient server front-end for the BuntDB and Tile38 projects.

Dec 1, 2022
A simple and lightweight encrypted password manager written in Go.
A simple and lightweight encrypted password manager written in Go.

A simple and lightweight encrypted password manager written in Go.

Jun 16, 2022
Remark42 is a self-hosted, lightweight, and simple comment engine
Remark42 is a self-hosted, lightweight, and simple comment engine

Remark42 is a self-hosted, lightweight, and simple (yet functional) comment engine, which doesn't spy on users. It can be embedded into blogs, articles or any other place where readers add comments.

Nov 28, 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

Nov 29, 2022
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

Dec 2, 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

Dec 2, 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

Nov 28, 2022
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

Nov 11, 2022