84 lines
2.5 KiB
Go
84 lines
2.5 KiB
Go
package response
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
apierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
|
)
|
|
|
|
// Result is the transport-independent input to an Encoder. Err is available for
|
|
// application error mapping; default encoders never expose it or its causes.
|
|
type Result struct {
|
|
Status int
|
|
Code, Message, RequestID string
|
|
Data any
|
|
Err error
|
|
BusinessCode any
|
|
Failed bool
|
|
}
|
|
|
|
// IsError preserves failure semantics independently of the HTTP status.
|
|
func (r Result) IsError() bool { return r.Failed || r.Err != nil || r.Status >= 400 }
|
|
|
|
// Payload is a complete response. Encoders must be safe for concurrent use.
|
|
// Status and headers are intentionally part of the contract: callback protocols
|
|
// may acknowledge an error using a different HTTP status or media type.
|
|
type Payload struct {
|
|
Status int
|
|
Header http.Header
|
|
Body []byte
|
|
}
|
|
|
|
type Encoder interface{ Encode(Result) (Payload, error) }
|
|
type EncoderFunc func(Result) (Payload, error)
|
|
|
|
func (f EncoderFunc) Encode(r Result) (Payload, error) { return f(r) }
|
|
|
|
func JSON(status int, value any) (Payload, error) {
|
|
data, err := json.Marshal(value)
|
|
if err != nil {
|
|
return Payload{}, err
|
|
}
|
|
return Payload{Status: status, Header: http.Header{"Content-Type": {"application/json; charset=utf-8"}}, Body: append(data, '\n')}, nil
|
|
}
|
|
|
|
func Text(status int, value string) Payload {
|
|
return Payload{Status: status, Header: http.Header{"Content-Type": {"text/plain; charset=utf-8"}}, Body: []byte(value)}
|
|
}
|
|
|
|
// Default is immutable; applications can use different encoders in one process.
|
|
var defaultEncoder = MustNew(Config{})
|
|
|
|
func Default() Encoder { return defaultEncoder }
|
|
|
|
// RawJSON leaves successful data unwrapped. Errors use the selected error
|
|
// policy; callback protocols with custom acknowledgments should use EncoderFunc.
|
|
type rawJSONEncoder struct{ errors Encoder }
|
|
|
|
func (e *rawJSONEncoder) ErrorRegistry() *apierrors.Registry {
|
|
if p, ok := e.errors.(ErrorRegistryProvider); ok {
|
|
return p.ErrorRegistry()
|
|
}
|
|
return nil
|
|
}
|
|
func (e *rawJSONEncoder) Encode(r Result) (Payload, error) {
|
|
if r.IsError() {
|
|
return e.errors.Encode(r)
|
|
}
|
|
return JSON(r.Status, r.Data)
|
|
}
|
|
func RawJSON(errors Encoder) Encoder {
|
|
if errors == nil {
|
|
errors = Default()
|
|
}
|
|
return &rawJSONEncoder{errors: errors}
|
|
}
|
|
|
|
func (e *rawJSONEncoder) ValidateErrors(catalog apierrors.Catalog) error {
|
|
if checker, ok := e.errors.(interface{ ValidateErrors(apierrors.Catalog) error }); ok {
|
|
return checker.ValidateErrors(catalog)
|
|
}
|
|
return nil
|
|
}
|