feat(web): httputil.WithStatus — configurable success status on the handler adapters (v1.5.0)
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
package httputil
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Option configures a Handle* adapter. With no options each adapter writes its
|
||||
// default success status (200 for the body-returning adapters, 204 for
|
||||
// [HandleEmpty]). Options are applied once at wiring time, not per request.
|
||||
type Option func(*options)
|
||||
|
||||
type options struct {
|
||||
status int
|
||||
}
|
||||
|
||||
// WithStatus overrides the success status an adapter writes — e.g.
|
||||
// WithStatus(http.StatusCreated) for a POST that creates a resource, or
|
||||
// WithStatus(http.StatusAccepted) for an async [HandleEmpty].
|
||||
//
|
||||
// It exists because the Handle* adapters own only the happy path: they always
|
||||
// write a success response, so the status is theirs to set, while error statuses
|
||||
// are derived separately from the returned xerror by [Error]. The code must
|
||||
// therefore be 2xx — anything else is a routing mistake, since an error status
|
||||
// never belongs on the success path. WithStatus panics on a non-2xx code, and
|
||||
// because routes are wired at startup that panic surfaces at boot: the service
|
||||
// fails to start rather than emitting a wrong status at request time. (mw.Recover
|
||||
// guards requests, so it does not catch a wiring-time panic — which is the point.)
|
||||
func WithStatus(code int) Option {
|
||||
if code < 200 || code > 299 {
|
||||
panic(fmt.Sprintf("httputil.WithStatus: success status must be 2xx, got %d", code))
|
||||
}
|
||||
return func(o *options) { o.status = code }
|
||||
}
|
||||
|
||||
// resolveStatus folds opts over the adapter's default success status.
|
||||
func resolveStatus(def int, opts []Option) int {
|
||||
o := options{status: def}
|
||||
for _, opt := range opts {
|
||||
opt(&o)
|
||||
}
|
||||
return o.status
|
||||
}
|
||||
Reference in New Issue
Block a user