71 lines
2.1 KiB
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)
|
|
}
|