feat: add project-owned error catalogs and HTTP 200 failure contracts
This commit is contained in:
@@ -3,6 +3,8 @@ 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
|
||||
@@ -12,8 +14,13 @@ type Result struct {
|
||||
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.
|
||||
@@ -47,14 +54,30 @@ 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 EncoderFunc(func(r Result) (Payload, error) {
|
||||
if r.Err != nil || r.Status >= 400 {
|
||||
return errors.Encode(r)
|
||||
}
|
||||
return JSON(r.Status, r.Data)
|
||||
})
|
||||
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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user