ginbump/middleware.go
func RateLimit(client *redis.Client, hasher speedbump.RateHasher, max int64) gin.HandlerFunc {
	limiter := speedbump.NewLimiter(client, hasher, max)

	return func(c *gin.Context) {
		// Attempt to perform the request
		ip, _, _ := net.SplitHostPort(c.Request.RemoteAddr)
		ok, err := limiter.Attempt(ip)

		if err != nil {
			panic(err)
		}

		if !ok {
			nextTime := time.Now().Add(hasher.Duration())

			c.JSON(429, gin.H{
				"status":   "error",
				"messages": []string{"Rate limit exceeded. Try again in " + humanize.Time(nextTime)},
			})
			c.Abort()
		}

		c.Next()

		// After the request
		// log.Print(ip + " was limited because it exceeded the max rate")
	}
}
func RateLimit(client *redis.Client, hasher speedbump.RateHasher, max int64) gin.HandlerFunc {
	limiter := speedbump.NewLimiter(client, hasher, max)

	return func(c *gin.Context) {
		// Attempt to perform the request
		ip, _, _ := net.SplitHostPort(c.Request.RemoteAddr)
		ok, err := limiter.Attempt(ip)

		if err != nil {
			panic(err)
		}

		if !ok {
			nextTime := time.Now().Add(hasher.Duration())

			c.JSON(429, gin.H{
				"status":   "error",
				"messages": []string{"Rate limit exceeded. Try again in " + humanize.Time(nextTime)},
			})
			c.Abort()
		}

		c.Next()

		// After the request
		// log.Print(ip + " was limited because it exceeded the max rate")
	}
}
// RateLimit is a Gin middleware for rate limitting incoming requests based on
// the client's IP address.
//
// The resulting middleware will use the client to talk to the Redis server.
// The hasher is used to keep track of counters and to provide an estimate of
// when the client should be able to do requests again. The limit per period is
// defined by the max.
//
// Response format
//
// Once a client reaches the imposed limit, they will receive a JSON response
// similar to the following:
//
//  {
//    "messages":["Rate limit exceeded. Try again in 1 minute from now"],
//    "status":"error"
//  }