| package apierrors |
|
|
| import ( |
| "context" |
| "encoding/json" |
| "fmt" |
| "net/http" |
| "strings" |
|
|
| "github.com/openmeterio/openmeter/api/v3/render" |
| ) |
|
|
| |
| type BaseAPIError struct { |
| |
| |
| |
| Type string `json:"type"` |
|
|
| |
| |
| Status int `json:"status"` |
|
|
| |
| |
| |
| Title string `json:"title"` |
|
|
| |
| |
| |
| Instance string `json:"instance"` |
|
|
| |
| |
| |
| |
| Detail string `json:"detail"` |
|
|
| |
| |
| |
| InvalidParameters InvalidParameters `json:"invalid_parameters,omitempty"` |
|
|
| |
| |
| UnderlyingError error `json:"-"` |
|
|
| |
| ctx context.Context |
| } |
|
|
| |
| type InvalidParameters []InvalidParameter |
|
|
| type InvalidParameterSource uint8 |
|
|
| const ( |
| InvalidParamSourcePath InvalidParameterSource = iota + 1 |
| InvalidParamSourceQuery |
| InvalidParamSourceBody |
| InvalidParamSourceHeader |
| ) |
|
|
| func (i InvalidParameterSource) String() string { |
| switch i { |
| case InvalidParamSourceBody: |
| return "body" |
| case InvalidParamSourcePath: |
| return "path" |
| case InvalidParamSourceHeader: |
| return "header" |
| case InvalidParamSourceQuery: |
| return "query" |
| } |
| return "" |
| } |
|
|
| func ToInvalid(s string) InvalidParameterSource { |
| switch s { |
| case "query": |
| return InvalidParamSourceQuery |
| case "path": |
| return InvalidParamSourcePath |
| case "body": |
| return InvalidParamSourceBody |
| case "header": |
| return InvalidParamSourceHeader |
| } |
| return InvalidParameterSource(0) |
| } |
|
|
| func (i InvalidParameterSource) MarshalJSON() ([]byte, error) { |
| return json.Marshal(i.String()) |
| } |
|
|
| func (i *InvalidParameterSource) UnmarshalJSON(data []byte) error { |
| var source string |
| if err := json.Unmarshal(data, &source); err != nil { |
| return err |
| } |
| *i = ToInvalid(source) |
| return nil |
| } |
|
|
| |
| type InvalidParameter struct { |
| |
| Field string `json:"field"` |
|
|
| |
| Rule string `json:"rule,omitempty"` |
|
|
| |
| Reason string `json:"reason"` |
|
|
| |
| Source InvalidParameterSource `json:"source"` |
|
|
| |
| Choices []string `json:"choices,omitempty"` |
|
|
| |
| |
| Minimum *int `json:"minimum,omitempty"` |
|
|
| |
| |
| Maximum *int `json:"maximum,omitempty"` |
|
|
| |
| |
| Dependents []string `json:"dependents,omitempty"` |
| } |
|
|
| |
| func (ips InvalidParameters) String() string { |
| out := new(strings.Builder) |
| for i, param := range ips { |
| out.WriteString(param.Field) |
| if param.Rule != "" { |
| _, _ = fmt.Fprintf(out, " [%s]", param.Rule) |
| } |
| _, _ = fmt.Fprintf(out, ": %s", param.Reason) |
| if i != len(ips)-1 { |
| _, _ = fmt.Fprintf(out, ", ") |
| } |
| } |
| return out.String() |
| } |
|
|
| |
| func (bae *BaseAPIError) Error() string { |
| switch { |
| case bae.InvalidParameters != nil: |
| return fmt.Sprintf("%s: %s", bae.UnderlyingError, bae.InvalidParameters.String()) |
| case bae.Detail != "" && bae.UnderlyingError != nil: |
| return fmt.Sprintf("%s: %s", bae.Detail, bae.UnderlyingError) |
| case bae.Detail != "": |
| return bae.Detail |
| } |
| if bae.UnderlyingError != nil { |
| return bae.UnderlyingError.Error() |
| } |
| return bae.Title |
| } |
|
|
| |
| func (bae *BaseAPIError) Unwrap() error { |
| return bae.UnderlyingError |
| } |
|
|
| |
| func (bae *BaseAPIError) Context() context.Context { |
| return bae.ctx |
| } |
|
|
| |
| func (bae *BaseAPIError) HandleAPIError( |
| w http.ResponseWriter, |
| r *http.Request, |
| ) { |
| _ = render.RenderJSON(w, bae, render.WithContentType(ContentTypeProblemValue), render.WithStatus(bae.Status)) |
| } |
|
|