| // Code generated by @openmeter/typespec-go. DO NOT EDIT. | |
| package openmeter | |
| import ( | |
| "encoding/json" | |
| "errors" | |
| "fmt" | |
| ) | |
| // ErrEmptyID is returned by operations that target a single resource when the | |
| // resource ID is empty. It is caught before any request is made so an omitted | |
| // ID surfaces as a clear client-side error rather than an ambiguous server | |
| // response. Match it with errors.Is. | |
| var ErrEmptyID = errors.New("openmeter: resource ID must not be empty") | |
| // APIError is returned for any non-2xx API response. It mirrors the API's | |
| // RFC 7807-style problem body. When the body cannot be parsed as such, Title is | |
| // left empty and RawBody carries the undecoded payload. | |
| type APIError struct { | |
| // StatusCode is the HTTP status code of the response. | |
| StatusCode int `json:"-"` | |
| // Status is the status code echoed in the problem body (usually equal to | |
| // StatusCode). | |
| Status int `json:"status"` | |
| // Title is a short, stable, human-readable summary of the problem. | |
| Title string `json:"title"` | |
| // Type is an optional machine-readable error type. | |
| Type string `json:"type,omitempty"` | |
| // Detail is a human-readable explanation specific to this occurrence. | |
| Detail string `json:"detail"` | |
| // Instance carries the correlation ID, formatted as kong:trace:<id>. | |
| Instance string `json:"instance"` | |
| // RawBody is the undecoded response body, always populated. | |
| RawBody []byte `json:"-"` | |
| } | |
| func newAPIError(statusCode int, body []byte) *APIError { | |
| e := &APIError{StatusCode: statusCode, RawBody: body} | |
| // Best-effort decode; a non-conforming body still yields a useful error via | |
| // StatusCode and RawBody. | |
| _ = json.Unmarshal(body, e) | |
| return e | |
| } | |
| // AsAPIError returns the APIError inside err, when err came from an API response. | |
| func AsAPIError(err error) (*APIError, bool) { | |
| var apiErr *APIError | |
| if errors.As(err, &apiErr) { | |
| return apiErr, true | |
| } | |
| return nil, false | |
| } | |
| // Decode decodes the original error response body into out. | |
| func (e *APIError) Decode(out any) error { | |
| return json.Unmarshal(e.RawBody, out) | |
| } | |
| // DecodeAPIError decodes an API error body into T. The returned boolean is false | |
| // when err is not an APIError. | |
| func DecodeAPIError[T any](err error) (T, bool, error) { | |
| var zero T | |
| apiErr, ok := AsAPIError(err) | |
| if !ok { | |
| return zero, false, nil | |
| } | |
| var out T | |
| if err := apiErr.Decode(&out); err != nil { | |
| return zero, true, err | |
| } | |
| return out, true, nil | |
| } | |
| func (e *APIError) Error() string { | |
| switch { | |
| case e.Title != "" && e.Detail != "": | |
| return fmt.Sprintf("openmeter: %d %s: %s", e.StatusCode, e.Title, e.Detail) | |
| case e.Title != "": | |
| return fmt.Sprintf("openmeter: %d %s", e.StatusCode, e.Title) | |
| default: | |
| // No RFC 7807 fields parsed (e.g. a proxy returned an HTML error page). | |
| // Inline the raw body for diagnostics but bound it so a large payload | |
| // can't blow up log lines; RawBody still holds the full response. | |
| const maxInline = 512 | |
| body := e.RawBody | |
| suffix := "" | |
| if len(body) > maxInline { | |
| body = body[:maxInline] | |
| suffix = "… (truncated)" | |
| } | |
| return fmt.Sprintf("openmeter: unexpected status %d: %s%s", e.StatusCode, string(body), suffix) | |
| } | |
| } | |