Skip to content

Commit 3a5107a

Browse files
authored
(MAINT) Add rate limit handler config. (#50)
(MAINT) Add rate limiting per handler.
1 parent 796c18f commit 3a5107a

File tree

2 files changed

+39
-9
lines changed

2 files changed

+39
-9
lines changed

pkg/service/README.md

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ type Config struct {
3838
ErrorHandler *MiddlewareHandler //Optional. If true a handler will be added to the end of the chain.
3939
}
4040
41-
//Handler will hold all the callback handlers to be registered. N.B. gin will be used.
41+
// Handler will hold all the callback handlers to be registered. N.B. gin will be used.
4242
type Handler struct {
43-
Method string //HTTP method or service.AnyMethod to support all limits.
44-
Path string //The path the endpoint runs on.
45-
Group string //Optional - specify a group if this is to have it's own group. N.B. The point of the group is to allow middleware to run on some requests and not others(based on the group).
46-
Handler func(c *gin.Context) //The handler to be used.
43+
Method string // HTTP method or service.AnyMethod to support all limits.
44+
Path string // The path the endpoint runs on.
45+
Group string // Optional - specify a group (used to control which middlewares will run)
46+
Handler func(c *gin.Context) // The handler to be used.
47+
RateLimitConfig *HandlerRateLimitConfig // Optional rate limiting config specifically for the handler.
4748
}
4849
4950
//MiddlewareHandler will hold all the middleware and whether
@@ -71,6 +72,12 @@ type CorsConfig struct {
7172
Enabled bool //Whether CORS is enabled or not.
7273
OverrideCfg *cors.Config //Optional. This is only required if you do not want to use the default CORS configuration.
7374
}
75+
76+
// HandlerRateLimitConfig holds the rate limiting config fo a sepecific handler.
77+
type HandlerRateLimitConfig struct {
78+
Limit int // The number of requests allowed within the timeframe.
79+
Within int // The timeframe(seconds) the requests are allowed in.
80+
}
7481
7582
//Service will be the actual structure returned.
7683
type Service struct {
@@ -82,6 +89,7 @@ type Service struct {
8289
#### Notes
8390
- The cors config and the handlers are based on the gin framework : https://github.com/gin-gonic/gin.
8491
- Rate limiting is done by the library github.com/cnjack/throttle.
92+
- Rate limiting can be added to a handler or on a per group basis.
8593
- The group principle is based on Gin routergroups. The idea behind it is that not all middleware needs to run on
8694
all requests so the middleware in a group will only run against an endpoint in that group.
8795
This is applied to cors, rate limiting and any middleware in general.

pkg/service/service.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ type Config struct {
4242

4343
// Handler will hold all the callback handlers to be registered. N.B. gin will be used.
4444
type Handler struct {
45-
Method string // HTTP method or service.AnyMethod to support all limits.
46-
Path string // The path the endpoint runs on.
47-
Group string // Optional - specify a group (used to control which middlewares will run)
48-
Handler func(c *gin.Context) // The handler to be used.
45+
Method string // HTTP method or service.AnyMethod to support all limits.
46+
Path string // The path the endpoint runs on.
47+
Group string // Optional - specify a group (used to control which middlewares will run)
48+
Handler func(c *gin.Context) // The handler to be used.
49+
RateLimitConfig *HandlerRateLimitConfig // Optional rate limiting config specifically for the handler.
4950
}
5051

5152
// MiddlewareHandler will hold a middleware handler and the groups on which it should be registered.
@@ -74,6 +75,12 @@ type CorsConfig struct {
7475
OverrideCfg *cors.Config // Optional. Only required if you do not want to use the default CORS configuration.
7576
}
7677

78+
// HandlerRateLimitConfig holds the rate limiting config fo a sepecific handler.
79+
type HandlerRateLimitConfig struct {
80+
Limit int // The number of requests allowed within the timeframe.
81+
Within int // The timeframe(seconds) the requests are allowed in.
82+
}
83+
7784
// Service will be the actual structure returned.
7885
type Service struct {
7986
*http.Server // Anonymous embedded struct to allow access to http server methods.
@@ -159,6 +166,10 @@ func setupRateLimiting(config *RateLimitConfig, engine *gin.Engine) {
159166
}
160167
}
161168

169+
func getRateLimitHandler(config *HandlerRateLimitConfig) gin.HandlerFunc {
170+
return rateLimitHandler(config.Limit, config.Within)
171+
}
172+
162173
func setupMiddleware(mwHandlers []MiddlewareHandler, engine *gin.Engine) {
163174
// Add middleware first then the handlers
164175
for _, handler := range mwHandlers {
@@ -199,6 +210,17 @@ func setupEndpoints(handlers []Handler, engine *gin.Engine) (err error) {
199210

200211
for _, handler := range handlers {
201212
handlerGroup := getRouterGroup(engine, handler.Group)
213+
214+
// Create a new group on the fly with the rate limiter as the first entry point and copy the chain of handlers.
215+
if handler.RateLimitConfig != nil {
216+
newHandlerGroup := engine.Group("/")
217+
218+
newHandlerGroup.Handlers = append([]gin.HandlerFunc{getRateLimitHandler(handler.RateLimitConfig)},
219+
handlerGroup.Handlers...)
220+
221+
handlerGroup = newHandlerGroup
222+
}
223+
202224
switch method := handler.Method; method {
203225
case http.MethodGet, http.MethodPost, http.MethodPatch, http.MethodDelete, http.MethodOptions:
204226
handlerGroup.Handle(method, handler.Path, handler.Handler)

0 commit comments

Comments
 (0)