package api import ( "fmt" "strings" ) // APIError is a task the gateway refused or could not complete. // // It carries the gateway's own code so the caller can react to a specific // failure (bad credentials, unknown zone, name server mismatch) without // matching on message text. type APIError struct { Code string Text string Object string Stid string } func (e *APIError) Error() string { var b strings.Builder if e.Code != "" { fmt.Fprintf(&b, "%s: %s", e.Code, e.Text) } else { b.WriteString(e.Text) } if e.Object != "" { fmt.Fprintf(&b, " (object: %s)", e.Object) } return b.String() } // fromResult builds an error from a failed result block. The actionable code // and text live in msg, not in status, so msg is preferred. func fromResult(r Result, stid string) *APIError { e := &APIError{Stid: stid} var pick *Msg for i := range r.Msg { m := &r.Msg[i] // A notification ("N") alongside an error ("E") is not the failure. if strings.EqualFold(m.Type, "error") || strings.HasPrefix(m.Code, "E") { pick = m break } if pick == nil { pick = m } } switch { case pick != nil && pick.Text != "": e.Code, e.Text = pick.Code, pick.Text case r.Status.Text != "": e.Code, e.Text = r.Status.Code, r.Status.Text default: e.Text = "the gateway reported a failure without a message" } if pick != nil && pick.Object != nil { e.Object = pick.Object.Type + " " + pick.Object.Value } return e }