Documentation
¶
Overview ¶
Package response provides Response-step middleware for CORS, caching, field transforms, custom envelopes, and observability.
Index ¶
- func AddHeader(key, value string) maniflex.MiddlewareFunc
- func CORSHeaders(allowedOrigins ...string) maniflex.MiddlewareFunc
- func CORSHeadersWithConfig(cfg CORSConfig) maniflex.MiddlewareFunc
- func Cache(maxAgeSeconds int) maniflex.MiddlewareFunc
- func Envelope(fn EnvelopeFunc) maniflex.MiddlewareFunc
- func Logging(logger *slog.Logger) maniflex.MiddlewareFunc
- func Metrics(collector MetricsCollector) maniflex.MiddlewareFunc
- func RedactField(field string, shouldRedact func(ctx *maniflex.ServerContext) bool) maniflex.MiddlewareFunc
- func TransformField(field string, fn TransformFunc) maniflex.MiddlewareFunc
- type CORSConfig
- type EnvelopeFunc
- type MetricsCollector
- type TransformFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AddHeader ¶
func AddHeader(key, value string) maniflex.MiddlewareFunc
AddHeader unconditionally adds an HTTP response header.
server.Pipeline.Response.Register(
response.AddHeader("X-Powered-By", "maniflex"),
maniflex.AtPosition(maniflex.After),
)
func CORSHeaders ¶
func CORSHeaders(allowedOrigins ...string) maniflex.MiddlewareFunc
CORSHeaders sets CORS response headers on every response, and returns 200 for OPTIONS preflight requests. Register this on the Response step with AtPosition(After).
At least one origin is required — pass explicit origins (recommended) or "*" to allow any origin. Calling it with no origins panics, so a permissive wildcard is never applied by accident (SEC-6). For credentials or custom allowed headers/methods/max-age, use CORSHeadersWithConfig.
server.Pipeline.Response.Register(
response.CORSHeaders("https://myapp.com"),
maniflex.AtPosition(maniflex.After),
)
func CORSHeadersWithConfig ¶ added in v0.1.4
func CORSHeadersWithConfig(cfg CORSConfig) maniflex.MiddlewareFunc
CORSHeadersWithConfig is CORSHeaders with full control over allowed headers, methods, preflight max-age, and credentials. cfg.AllowOrigins is required (empty panics), and a "*" origin combined with AllowCredentials panics because browsers reject that combination.
server.Pipeline.Response.Register(
response.CORSHeadersWithConfig(response.CORSConfig{
AllowOrigins: []string{"https://myapp.com"},
AllowCredentials: true,
}),
maniflex.AtPosition(maniflex.After),
)
func Cache ¶
func Cache(maxAgeSeconds int) maniflex.MiddlewareFunc
Cache sets Cache-Control and ETag headers on read responses. It is a no-op on write operations (create, update, delete).
server.Pipeline.Response.Register(
response.Cache(300), // 5 minutes
maniflex.ForOperation(maniflex.OpRead, maniflex.OpList),
maniflex.AtPosition(maniflex.After),
)
func Envelope ¶
func Envelope(fn EnvelopeFunc) maniflex.MiddlewareFunc
Envelope replaces the default {"data": ..., "meta": ...} response structure with a custom one. Register it with AtPosition(After) on the Response step.
server.Pipeline.Response.Register(
response.Envelope(func(ctx *maniflex.ServerContext, data any, meta *maniflex.ResponseMeta) any {
out := map[string]any{"result": data, "ok": true}
if meta != nil {
out["pagination"] = meta
}
return out
}),
maniflex.AtPosition(maniflex.After),
)
func Logging ¶
func Logging(logger *slog.Logger) maniflex.MiddlewareFunc
Logging emits a structured log line after every request using slog. Register it with AtPosition(After) on the Response step.
server.Pipeline.Response.Register(
response.Logging(slog.Default()),
maniflex.AtPosition(maniflex.After),
)
func Metrics ¶
func Metrics(collector MetricsCollector) maniflex.MiddlewareFunc
Metrics records request counters and latency histograms. Register it with AtPosition(After) on the Response step.
server.Pipeline.Response.Register(
response.Metrics(myCollector),
maniflex.AtPosition(maniflex.After),
)
func RedactField ¶
func RedactField(field string, shouldRedact func(ctx *maniflex.ServerContext) bool) maniflex.MiddlewareFunc
RedactField removes a field from the response dynamically, based on a condition. Unlike the static mfx:"hidden" tag this can check ctx.Auth.
// Hide phone unless the caller has the "support" role
server.Pipeline.Response.Register(
response.RedactField("phone", func(ctx *maniflex.ServerContext) bool {
return !ctx.HasRole("support")
}),
maniflex.ForModel("User"),
maniflex.AtPosition(maniflex.After),
)
func TransformField ¶
func TransformField(field string, fn TransformFunc) maniflex.MiddlewareFunc
TransformField applies fn to the named field in every item of the response data. Works on both single-record and list responses.
// Prefix avatar URLs with a CDN base
server.Pipeline.Response.Register(
response.TransformField("avatar_url", func(v any) any {
if s, ok := v.(string); ok && s != "" {
return "https://cdn.example.com/" + s
}
return v
}),
maniflex.ForModel("User"),
maniflex.AtPosition(maniflex.After),
)
Types ¶
type CORSConfig ¶
type CORSConfig struct {
// AllowOrigins is the list of allowed origins. It is REQUIRED: construction
// panics if it is empty, so a permissive wildcard is never applied by
// accident. Use ["*"] to explicitly allow any origin (public APIs only — it
// cannot be combined with AllowCredentials).
AllowOrigins []string
// AllowHeaders are the headers a browser may send. Default: common safe set.
AllowHeaders []string
// AllowMethods are the HTTP methods to allow. Default: GET, POST, PATCH, DELETE, OPTIONS.
AllowMethods []string
// MaxAge is the preflight cache duration in seconds. Default: 86400 (24h).
MaxAge int
// AllowCredentials sets Access-Control-Allow-Credentials. Default: false.
// It cannot be combined with a "*" wildcard origin (the Fetch spec forbids
// that combination); doing so panics at construction.
AllowCredentials bool
}
CORSConfig configures CORS header behaviour.
type EnvelopeFunc ¶
type EnvelopeFunc func(ctx *maniflex.ServerContext, data any, meta *maniflex.ResponseMeta) any
EnvelopeFunc wraps the outgoing response data in a custom structure. Return a new map to replace the default {"data": ...} envelope.
type MetricsCollector ¶
type MetricsCollector interface {
// IncCounter increments a counter with the given labels.
IncCounter(name string, labels map[string]string)
// ObserveHistogram records a duration observation.
ObserveHistogram(name string, value float64, labels map[string]string)
}
MetricsCollector is satisfied by any metrics library. Implement it to bridge to Prometheus, Datadog, StatsD, etc.
type TransformFunc ¶
TransformFunc maps one field value to another in the response.