Skip to content

Commit

Permalink
feat: improve error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
abemedia committed May 5, 2023
1 parent 5bd82f6 commit 0c6fee1
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 57 deletions.
4 changes: 2 additions & 2 deletions encoding/text/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ func encode(ctx *fasthttp.RequestCtx, v any) error {
b = strconv.AppendFloat(ctx.Response.Body(), v, 'f', -1, 64)
case bool:
b = strconv.AppendBool(ctx.Response.Body(), v)
case error:
b = byteconv.Atob(v.Error())
case encoding.TextMarshaler:
b, err = v.MarshalText()
case error:
b = byteconv.Atob(v.Error())
case fmt.Stringer:
b = append(ctx.Response.Body(), v.String()...)
default:
Expand Down
41 changes: 5 additions & 36 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ func (e *HTTPError) Error() string {
}

func (e *HTTPError) StatusCode() int {
if e.code != 0 {
return e.code
}

var sc StatusCoder
if errors.As(e.err, &sc) {
return sc.StatusCode()
}

if e.code == 0 {
return http.StatusInternalServerError
}

return e.code
return http.StatusInternalServerError
}

func (e *HTTPError) MarshalText() ([]byte, error) {
Expand Down Expand Up @@ -117,34 +117,3 @@ func (e StatusError) Error() string {
func (e StatusError) StatusCode() int {
return int(e)
}

func (e StatusError) MarshalText() ([]byte, error) {
return byteconv.Atob(e.Error()), nil
}

func (e StatusError) MarshalJSON() ([]byte, error) {
var buf bytes.Buffer

buf.WriteString(`{"message":`)
buf.WriteString(strconv.Quote(e.Error()))
buf.WriteRune('}')

return buf.Bytes(), nil
}

func (e StatusError) MarshalXML(enc *xml.Encoder, _ xml.StartElement) error {
start := xml.StartElement{Name: xml.Name{Local: "message"}}
return enc.EncodeElement(e.Error(), start)
}

func (e StatusError) MarshalYAML() (any, error) {
return map[string]string{"message": e.Error()}, nil
}

var (
_ error = (*StatusError)(nil)
_ encoding.TextMarshaler = (*StatusError)(nil)
_ json.Marshaler = (*StatusError)(nil)
_ xml.Marshaler = (*StatusError)(nil)
_ yaml.Marshaler = (*StatusError)(nil)
)
38 changes: 19 additions & 19 deletions handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,18 +55,16 @@ func H[T, O any](handle Handle[T, O]) httprouter.Handle { //nolint:gocognit,cycl
return
}

req := new(T)

var (
req = new(T)
res any
e *HTTPError
)

// Decode the header.
if decodeHeader != nil {
err = decodeHeader.Decode(&ctx.Request.Header, req)
if err != nil {
e = Error(err, http.StatusBadRequest)
res = Error(err, http.StatusBadRequest)
goto Encode
}
}
Expand All @@ -76,7 +74,7 @@ func H[T, O any](handle Handle[T, O]) httprouter.Handle { //nolint:gocognit,cycl
if q := ctx.URI().QueryArgs(); q.Len() > 0 {
err := decodeQuery.Decode(q, req)
if err != nil {
e = Error(err, http.StatusBadRequest)
res = Error(err, http.StatusBadRequest)
goto Encode
}
}
Expand All @@ -86,7 +84,7 @@ func H[T, O any](handle Handle[T, O]) httprouter.Handle { //nolint:gocognit,cycl
if decodePath != nil && len(p) != 0 {
err := decodePath.Decode(p, req)
if err != nil {
e = Error(err, http.StatusBadRequest)
res = Error(ErrNotFound, 0)
goto Encode
}
}
Expand All @@ -95,28 +93,24 @@ func H[T, O any](handle Handle[T, O]) httprouter.Handle { //nolint:gocognit,cycl
if ctx.Request.Header.ContentLength() > 0 {
dec, err := getDecoder(getEncoding(ctx.Request.Header.ContentType()))
if err != nil {
res = err
res = Error(err, 0)
goto Encode
}

if err := dec(ctx, req); err != nil {
e = Error(err, http.StatusBadRequest)
res = Error(err, getStatusCode(err, http.StatusBadRequest))
goto Encode
}
}

res, err = handle(ctx, *req)
if err != nil {
e = Error(err, 0)
res = Error(err, 0)
}

Encode:
ctx.SetContentType(contentType + "; charset=utf-8")

if e != nil {
res = e
}

if h, ok := res.(Headerer); ok {
for k, v := range h.Header() {
ctx.Response.Header.Set(k, v[0])
Expand All @@ -139,13 +133,12 @@ func H[T, O any](handle Handle[T, O]) httprouter.Handle { //nolint:gocognit,cycl
}

func handleError(ctx *fasthttp.RequestCtx, err error) {
if statusCoder, ok := err.(StatusCoder); ok { //nolint:errorlint
if sc := statusCoder.StatusCode(); sc < http.StatusInternalServerError {
ctx.Error(err.Error()+"\n", sc)
return
}
code := getStatusCode(err, http.StatusInternalServerError)
if code < http.StatusInternalServerError {
ctx.Error(err.Error()+"\n", code)
return
}
ctx.Error(fasthttp.StatusMessage(http.StatusInternalServerError)+"\n", http.StatusInternalServerError)
ctx.Error(fasthttp.StatusMessage(code)+"\n", code)
ctx.Logger().Printf("%v", err)
}

Expand All @@ -158,6 +151,13 @@ func getEncoding(b []byte) string {
return byteconv.Btoa(bytes.TrimSpace(b))
}

func getStatusCode(i any, fallback int) int {
if sc, ok := i.(StatusCoder); ok {
return sc.StatusCode()
}
return fallback
}

const (
headerTag = "header"
pathTag = "path"
Expand Down

0 comments on commit 0c6fee1

Please sign in to comment.