I have a service object similar to the one shown below which is exposed through HTTP:
type ComputeService struct {
}
func (svc ComputeService) Compute(userType string, data Data) (Result, error) {
// rate limit based on userType (both check and increment counter)
// if not rate limited, compute and return result
}
Now, as you can see rate-limiting needs to be done based on userType
. Implementation of rate limiter itself changes according to userType
. I am thinking of 2 approaches of resolving the rate limiter using userType
.
// First approach: for each request new ComputeService object is
// created after resolving RateLimiter using userType in the handler
// itself
type ComputeService struct {
RateLimiter RateLimiter
}
// Second approach: ComputeService object is initialized during startup
// and only RateLimiter is resolved with every Compute() call by calling
// the provider function
type ComputeService struct {
RateLimiterProvider func(userType string) RateLimiter
}
Both are testable. Which one would be preferable ? I'm leaning towards the 2nd approach since using it would mean that the handler will be purely read request, delegate to service, write out the response whereas in 1st approach, handler would contain additional step of resolving the rate limiter implementation.