influxdb/kit/feature/middleware.go

71 lines
2.1 KiB
Go

package feature
import (
"context"
"encoding/json"
"net/http"
"go.uber.org/zap"
)
// Handler is a middleware that annotates the context with a map of computed feature flags.
// To accurately compute identity-scoped flags, this middleware should be executed after any
// authorization middleware has annotated the request context with an authorizer.
type Handler struct {
log *zap.Logger
next http.Handler
flagger Flagger
flags []Flag
}
// NewHandler returns a configured feature flag middleware that will annotate request context
// with a computed map of the given flags using the provided Flagger.
func NewHandler(log *zap.Logger, flagger Flagger, flags []Flag, next http.Handler) http.Handler {
return &Handler{
log: log,
next: next,
flagger: flagger,
flags: flags,
}
}
// ServeHTTP annotates the request context with a map of computed feature flags before
// continuing to serve the request.
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx, err := Annotate(r.Context(), h.flagger, h.flags...)
if err != nil {
h.log.Warn("Unable to annotate context with feature flags", zap.Error(err))
} else {
r = r.WithContext(ctx)
}
if h.next != nil {
h.next.ServeHTTP(w, r)
}
}
// HTTPErrorHandler is an influxdb.HTTPErrorHandler. It's defined here instead
// of referencing the other interface type, because we want to try our best to
// avoid cyclical dependencies when feature package is used throughout the
// codebase.
type HTTPErrorHandler interface {
HandleHTTPError(ctx context.Context, err error, w http.ResponseWriter)
}
// NewFlagsHandler returns a handler that returns the map of computed feature flags on the request context.
func NewFlagsHandler(errorHandler HTTPErrorHandler, byKey ByKeyFn) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK)
var (
ctx = r.Context()
flags = ExposedFlagsFromContext(ctx, byKey)
)
if err := json.NewEncoder(w).Encode(flags); err != nil {
errorHandler.HandleHTTPError(ctx, err, w)
}
}
return http.HandlerFunc(fn)
}