pronounss/backend/server/error_v2.go

122 lines
3 KiB
Go
Raw Normal View History

2023-12-27 00:56:11 +01:00
package server
import (
"encoding/json"
2023-12-27 00:56:11 +01:00
"fmt"
json2 "github.com/aarondl/json"
2023-12-27 00:56:11 +01:00
"github.com/getsentry/sentry-go"
)
// An error returned by version 2 of the API.
type APIError2 struct {
Code int `json:"code"`
ID *sentry.EventID `json:"id,omitempty"`
Message string `json:"message,omitempty"`
Details string `json:"details,omitempty"`
Errors map[string][]ModelParseError `json:"errors,omitempty"`
RatelimitReset *int `json:"ratelimit_reset,omitempty"`
Status int `json:"-"`
}
func (e APIError2) Error() string {
if e.Message == "" {
e.Message = errCodeMessages[e.Code]
}
if e.Details != "" {
return fmt.Sprintf("%s (code: %d) (%s)", e.Message, e.Code, e.Details)
}
return fmt.Sprintf("%s (code: %d)", e.Message, e.Code)
}
// Returns a new error in APIv2 format.
func NewV2Error(code int, details string, parseErrors ...ModelParseError) APIError2 {
var errors map[string][]ModelParseError
if len(parseErrors) != 0 {
errors = make(map[string][]ModelParseError)
for _, p := range parseErrors {
errors[p.Key] = append(errors[p.Key], p)
}
}
return APIError2{
Code: code,
Message: errCodeMessages[code],
Details: details,
Errors: errors,
Status: errCodeStatuses[code],
}
}
type ModelParseError struct {
Message string `json:"message,omitempty"`
MaxLength int `json:"max_length,omitempty"`
ActualLength int `json:"actual_length,omitempty"`
ExpectedValues []any `json:"expected_values,omitempty"`
ActualValue any `json:"actual_value,omitempty"`
ExpectedType string `json:"expected_type,omitempty"`
ActualType string `json:"actual_type,omitempty"`
2023-12-27 00:56:11 +01:00
Key string `json:"-"`
}
func NewModelParseError(key, message string) ModelParseError {
return NewModelParseErrorWithLength(key, message, 0, 0)
}
func NewModelParseErrorWithLength(key, message string, maxLength, actualLength int) ModelParseError {
return ModelParseError{
Key: key,
Message: message,
MaxLength: maxLength,
ActualLength: actualLength,
}
}
func NewModelParseErrorWithValues(key, message string, expectedValues []any, actualValue any) ModelParseError {
return ModelParseError{
Key: key,
Message: message,
ExpectedValues: expectedValues,
ActualValue: actualValue,
}
}
func ParseJSONError(err error) *ModelParseError {
switch pe := err.(type) {
case *json.UnmarshalTypeError:
key := pe.Field
if key == "" {
key = "parse"
}
return &ModelParseError{
Key: key,
ExpectedType: pe.Type.String(),
ActualType: pe.Value,
}
case *json2.UnmarshalTypeError:
// TODO: remove the need for this, somehow
// This seems to be a bug in the
key := pe.Field
if key == "" {
key = "parse"
}
return &ModelParseError{
Key: key,
Message: "Invalid type passed for a field. Make sure your types match those in the documentation.",
ExpectedType: pe.Type.String(),
ActualType: pe.Value,
}
}
return nil
}