github.com/abemedia/go-don@v0.2.2-0.20240329015135-be88e32bb73b/errors.go (about)

     1  package don
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding"
     7  	"encoding/xml"
     8  	"errors"
     9  	"strconv"
    10  
    11  	"github.com/abemedia/go-don/internal/byteconv"
    12  	"github.com/goccy/go-json"
    13  	"github.com/valyala/fasthttp"
    14  	"gopkg.in/yaml.v3"
    15  )
    16  
    17  func E(err error) fasthttp.RequestHandler {
    18  	h := H(func(context.Context, any) (any, error) { return nil, err })
    19  	return func(ctx *fasthttp.RequestCtx) { h(ctx, nil) }
    20  }
    21  
    22  type HTTPError struct {
    23  	err  error
    24  	code int
    25  }
    26  
    27  func Error(err error, code int) *HTTPError {
    28  	return &HTTPError{err, code}
    29  }
    30  
    31  func (e *HTTPError) Error() string {
    32  	return e.err.Error()
    33  }
    34  
    35  func (e *HTTPError) Is(err error) bool {
    36  	return errors.Is(e.err, err) || errors.Is(StatusError(e.code), err)
    37  }
    38  
    39  func (e *HTTPError) Unwrap() error {
    40  	return e.err
    41  }
    42  
    43  func (e *HTTPError) StatusCode() int {
    44  	if e.code != 0 {
    45  		return e.code
    46  	}
    47  
    48  	var sc StatusCoder
    49  	if errors.As(e.err, &sc) {
    50  		return sc.StatusCode()
    51  	}
    52  
    53  	return fasthttp.StatusInternalServerError
    54  }
    55  
    56  func (e *HTTPError) MarshalText() ([]byte, error) {
    57  	var m encoding.TextMarshaler
    58  	if errors.As(e.err, &m) {
    59  		return m.MarshalText()
    60  	}
    61  
    62  	return byteconv.Atob(e.Error()), nil
    63  }
    64  
    65  func (e *HTTPError) MarshalJSON() ([]byte, error) {
    66  	var m json.Marshaler
    67  	if errors.As(e.err, &m) {
    68  		return m.MarshalJSON()
    69  	}
    70  
    71  	var buf bytes.Buffer
    72  	buf.WriteString(`{"message":`)
    73  	buf.WriteString(strconv.Quote(e.Error()))
    74  	buf.WriteRune('}')
    75  
    76  	return buf.Bytes(), nil
    77  }
    78  
    79  func (e *HTTPError) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {
    80  	var m xml.Marshaler
    81  	if errors.As(e.err, &m) {
    82  		return m.MarshalXML(enc, start)
    83  	}
    84  
    85  	start = xml.StartElement{Name: xml.Name{Local: "message"}}
    86  	return enc.EncodeElement(e.Error(), start)
    87  }
    88  
    89  func (e *HTTPError) MarshalYAML() (any, error) {
    90  	var m yaml.Marshaler
    91  	if errors.As(e.err, &m) {
    92  		return m.MarshalYAML()
    93  	}
    94  
    95  	return map[string]string{"message": e.Error()}, nil
    96  }
    97  
    98  var (
    99  	_ error                  = (*HTTPError)(nil)
   100  	_ encoding.TextMarshaler = (*HTTPError)(nil)
   101  	_ json.Marshaler         = (*HTTPError)(nil)
   102  	_ xml.Marshaler          = (*HTTPError)(nil)
   103  	_ yaml.Marshaler         = (*HTTPError)(nil)
   104  )
   105  
   106  // StatusError creates an error from an HTTP status code.
   107  type StatusError int
   108  
   109  const (
   110  	ErrBadRequest           = StatusError(fasthttp.StatusBadRequest)
   111  	ErrUnauthorized         = StatusError(fasthttp.StatusUnauthorized)
   112  	ErrForbidden            = StatusError(fasthttp.StatusForbidden)
   113  	ErrNotFound             = StatusError(fasthttp.StatusNotFound)
   114  	ErrMethodNotAllowed     = StatusError(fasthttp.StatusMethodNotAllowed)
   115  	ErrNotAcceptable        = StatusError(fasthttp.StatusNotAcceptable)
   116  	ErrConflict             = StatusError(fasthttp.StatusConflict)
   117  	ErrUnsupportedMediaType = StatusError(fasthttp.StatusUnsupportedMediaType)
   118  	ErrInternalServerError  = StatusError(fasthttp.StatusInternalServerError)
   119  )
   120  
   121  func (e StatusError) Error() string {
   122  	return fasthttp.StatusMessage(int(e))
   123  }
   124  
   125  func (e StatusError) StatusCode() int {
   126  	return int(e)
   127  }