feat: add typed error message templates and stable replay snapshots
This commit is contained in:
71
errors/snapshot.go
Normal file
71
errors/snapshot.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package apierrors
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// Snapshot contains only the resolved public error, suitable for replay
|
||||
// metadata. Parameters and internal causes are deliberately excluded.
|
||||
type Snapshot struct {
|
||||
Status int `json:"status"`
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
BusinessCode any `json:"businessCode,omitempty"`
|
||||
}
|
||||
|
||||
// Encode the public code as opaque JSON text so shared stores (including Redis
|
||||
// Lua/cjson) cannot round an int64 while rewriting their record envelopes.
|
||||
func (s Snapshot) MarshalJSON() ([]byte, error) {
|
||||
var encoded string
|
||||
if s.BusinessCode != nil {
|
||||
code, err := normalizeCatalogCode(s.BusinessCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw, err := json.Marshal(code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encoded = string(raw)
|
||||
}
|
||||
return json.Marshal(struct {
|
||||
Status int `json:"status"`
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
BusinessCodeJSON string `json:"businessCodeJson,omitempty"`
|
||||
}{s.Status, s.Code, s.Message, encoded})
|
||||
}
|
||||
func (s *Snapshot) UnmarshalJSON(data []byte) error {
|
||||
type plain Snapshot
|
||||
var out struct {
|
||||
plain
|
||||
BusinessCodeJSON string `json:"businessCodeJson,omitempty"`
|
||||
}
|
||||
if err := DecodeCatalogJSON(data, &out); err != nil {
|
||||
return err
|
||||
}
|
||||
if out.BusinessCodeJSON != "" {
|
||||
if err := DecodeCatalogJSON([]byte(out.BusinessCodeJSON), &out.BusinessCode); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if out.BusinessCode != nil {
|
||||
code, err := normalizeCatalogCode(out.BusinessCode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
out.BusinessCode = code
|
||||
}
|
||||
*s = Snapshot(out.plain)
|
||||
return nil
|
||||
}
|
||||
func (e *APIError) Snapshot() *Snapshot {
|
||||
if e == nil {
|
||||
return nil
|
||||
}
|
||||
return &Snapshot{Status: e.Status, Code: e.Code, Message: e.Message, BusinessCode: e.BusinessCode}
|
||||
}
|
||||
func (s *Snapshot) ErrorValue() *APIError {
|
||||
if s == nil {
|
||||
return nil
|
||||
}
|
||||
return &APIError{Status: s.Status, Code: s.Code, Message: s.Message, BusinessCode: s.BusinessCode}
|
||||
}
|
||||
Reference in New Issue
Block a user