...

Source file src/github.com/gin-gonic/gin/errors.go

Documentation: github.com/gin-gonic/gin

     1  // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
     2  // Use of this source code is governed by a MIT style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gin
     6  
     7  import (
     8  	"fmt"
     9  	"reflect"
    10  	"strings"
    11  
    12  	"github.com/gin-gonic/gin/internal/json"
    13  )
    14  
    15  // ErrorType is an unsigned 64-bit error code as defined in the gin spec.
    16  type ErrorType uint64
    17  
    18  const (
    19  	// ErrorTypeBind is used when Context.Bind() fails.
    20  	ErrorTypeBind ErrorType = 1 << 63
    21  	// ErrorTypeRender is used when Context.Render() fails.
    22  	ErrorTypeRender ErrorType = 1 << 62
    23  	// ErrorTypePrivate indicates a private error.
    24  	ErrorTypePrivate ErrorType = 1 << 0
    25  	// ErrorTypePublic indicates a public error.
    26  	ErrorTypePublic ErrorType = 1 << 1
    27  	// ErrorTypeAny indicates any other error.
    28  	ErrorTypeAny ErrorType = 1<<64 - 1
    29  	// ErrorTypeNu indicates any other error.
    30  	ErrorTypeNu = 2
    31  )
    32  
    33  // Error represents a error's specification.
    34  type Error struct {
    35  	Err  error
    36  	Type ErrorType
    37  	Meta any
    38  }
    39  
    40  type errorMsgs []*Error
    41  
    42  var _ error = (*Error)(nil)
    43  
    44  // SetType sets the error's type.
    45  func (msg *Error) SetType(flags ErrorType) *Error {
    46  	msg.Type = flags
    47  	return msg
    48  }
    49  
    50  // SetMeta sets the error's meta data.
    51  func (msg *Error) SetMeta(data any) *Error {
    52  	msg.Meta = data
    53  	return msg
    54  }
    55  
    56  // JSON creates a properly formatted JSON
    57  func (msg *Error) JSON() any {
    58  	jsonData := H{}
    59  	if msg.Meta != nil {
    60  		value := reflect.ValueOf(msg.Meta)
    61  		switch value.Kind() {
    62  		case reflect.Struct:
    63  			return msg.Meta
    64  		case reflect.Map:
    65  			for _, key := range value.MapKeys() {
    66  				jsonData[key.String()] = value.MapIndex(key).Interface()
    67  			}
    68  		default:
    69  			jsonData["meta"] = msg.Meta
    70  		}
    71  	}
    72  	if _, ok := jsonData["error"]; !ok {
    73  		jsonData["error"] = msg.Error()
    74  	}
    75  	return jsonData
    76  }
    77  
    78  // MarshalJSON implements the json.Marshaller interface.
    79  func (msg *Error) MarshalJSON() ([]byte, error) {
    80  	return json.Marshal(msg.JSON())
    81  }
    82  
    83  // Error implements the error interface.
    84  func (msg Error) Error() string {
    85  	return msg.Err.Error()
    86  }
    87  
    88  // IsType judges one error.
    89  func (msg *Error) IsType(flags ErrorType) bool {
    90  	return (msg.Type & flags) > 0
    91  }
    92  
    93  // Unwrap returns the wrapped error, to allow interoperability with errors.Is(), errors.As() and errors.Unwrap()
    94  func (msg *Error) Unwrap() error {
    95  	return msg.Err
    96  }
    97  
    98  // ByType returns a readonly copy filtered the byte.
    99  // ie ByType(gin.ErrorTypePublic) returns a slice of errors with type=ErrorTypePublic.
   100  func (a errorMsgs) ByType(typ ErrorType) errorMsgs {
   101  	if len(a) == 0 {
   102  		return nil
   103  	}
   104  	if typ == ErrorTypeAny {
   105  		return a
   106  	}
   107  	var result errorMsgs
   108  	for _, msg := range a {
   109  		if msg.IsType(typ) {
   110  			result = append(result, msg)
   111  		}
   112  	}
   113  	return result
   114  }
   115  
   116  // Last returns the last error in the slice. It returns nil if the array is empty.
   117  // Shortcut for errors[len(errors)-1].
   118  func (a errorMsgs) Last() *Error {
   119  	if length := len(a); length > 0 {
   120  		return a[length-1]
   121  	}
   122  	return nil
   123  }
   124  
   125  // Errors returns an array with all the error messages.
   126  // Example:
   127  //
   128  //	c.Error(errors.New("first"))
   129  //	c.Error(errors.New("second"))
   130  //	c.Error(errors.New("third"))
   131  //	c.Errors.Errors() // == []string{"first", "second", "third"}
   132  func (a errorMsgs) Errors() []string {
   133  	if len(a) == 0 {
   134  		return nil
   135  	}
   136  	errorStrings := make([]string, len(a))
   137  	for i, err := range a {
   138  		errorStrings[i] = err.Error()
   139  	}
   140  	return errorStrings
   141  }
   142  
   143  func (a errorMsgs) JSON() any {
   144  	switch length := len(a); length {
   145  	case 0:
   146  		return nil
   147  	case 1:
   148  		return a.Last().JSON()
   149  	default:
   150  		jsonData := make([]any, length)
   151  		for i, err := range a {
   152  			jsonData[i] = err.JSON()
   153  		}
   154  		return jsonData
   155  	}
   156  }
   157  
   158  // MarshalJSON implements the json.Marshaller interface.
   159  func (a errorMsgs) MarshalJSON() ([]byte, error) {
   160  	return json.Marshal(a.JSON())
   161  }
   162  
   163  func (a errorMsgs) String() string {
   164  	if len(a) == 0 {
   165  		return ""
   166  	}
   167  	var buffer strings.Builder
   168  	for i, msg := range a {
   169  		fmt.Fprintf(&buffer, "Error #%02d: %s\n", i+1, msg.Err)
   170  		if msg.Meta != nil {
   171  			fmt.Fprintf(&buffer, "     Meta: %v\n", msg.Meta)
   172  		}
   173  	}
   174  	return buffer.String()
   175  }
   176  

View as plain text