I'm working on a custom middleware for traefik that serves as a base for other sub-middlewares. Each sub-middleware implements an interface and has its own config structure. Here's an outline of my current setup:
// Sub-middleware interface
type INETMiddleware interface {
ServeHTTP(w http.ResponseWriter, r *http.Request) *sperrors.Error
}
// Configuration for the middleware
type INETConfig struct {
*INETSession
*INETGeoBlock
*INETAntibot
*INETHelloWorld
InternalErrorHTMLFilePath string `json:"internalErrorHTMLFilePath" toml:"internalErrorHTMLFilePath" yaml:"internalErrorHTMLFilePath"`
}
// Example sub-middleware config
type INETHelloWorld struct {
Message string `json:"message" toml:"message" yaml:"message"`
}
Each sub-middleware is initialized and executed in the main middleware like this:
BaseMiddleware struct {
next http.Handler
name string
mws []INETMiddleware
internalErrorTemplate string
logger *zerolog.Logger
}
func New(
ctx context.Context,
next http.Handler,
cfg dynamic.INETConfig,
name string,
) (*BaseMiddleware, error) {
mws := []INETMiddleware{}
// Adding sub-middleware
if cfg.INETAntibot != nil {
mw, err := antibot.New(ctx, next, *cfg.INETAntibot, name, cacheService, sessionService)
if err != nil {
return nil, err
}
mws = append(mws, mw)
}
// More sub-middleware can be added here...
return &BaseMiddleware{next: next, mws: mws, ...}, nil
}
func (b *BaseMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
for _, mw := range b.mws {
err := mw.ServeHTTP(w, r)
if err == nil {
continue
}
if err.IsHandled() {
return
}
b.logger.Err(err).Msgf("middleware: %s", err)
b.handleInternalServeHTTP(w)
return
}
b.next.ServeHTTP(w, r)
}
The problem is that i have to manually add each sub-middleware by checking the config and appending it to the list. This make it tedious to add new sub-middleware in the future.
Goal:
- Make the process of adding sub-middleware more modular and less repetitive.
- Each sub-middleware should have its own config structure and be easily added/removed without modifying the main middleware much.
Questions:
- How can I refactor this setup to make it easier to add new sub-middleware?
- Are there any patterns or best practices in Go or middleware design that could simplify this process?
Thanks for your help!
I try to implement chain of responsibility pattern middleware but the current i see its does not differ much
and read some links https://drstearns.github.io/tutorials/gomiddleware/ https://medium.com/@matryer/writing-middleware-in-golang-and-how-go-makes-it-so-much-fun-4375c1246e81
But dont know how to implment this will make its better