Skip to content

unhandled error unpacking #5

@zeromake

Description

@zeromake

demo:

package main

import (
	"context"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/pingcap/fn"
	"github.com/pkg/errors"
)

var (
	// ErrTest define an error
	ErrTest = errors.New("test")
	errs    = map[error]int{
		ErrTest: 1001,
	}
)

// Unknown default error code
const Unknown = 1000

type statusCodeError struct {
	err        error
	statusCode int
}

func (s *statusCodeError) StatusCode() int {
	return s.statusCode
}

func (s *statusCodeError) Error() string {
	return s.err.Error()
}

func (s *statusCodeError) Unwrap() error {
	return s.err
}

// ErrorWithStatusCode Rewrite
func ErrorWithStatusCode(err error, statusCode int) error {
	return &statusCodeError{err, statusCode}
}

// Error1 fn.ErrorWithStatusCode wrapped error cannot be unpacked to the original error
func Error1() (string, error) {
	return "", fn.ErrorWithStatusCode(errors.WithStack(ErrTest), 500)
}

// Error2 ErrorWithStatusCode rewrite and implement the `StatusCode`, `Unwrap` interface to support the original error
func Error2() (string, error) {
	return "", ErrorWithStatusCode(errors.WithStack(ErrTest), 500)
}

// Error3 The ErrorWithStatusCode error can no longer be set with a status code if it is wrapped.
func Error3() (string, error) {
	return "", errors.WithStack(ErrorWithStatusCode(ErrTest, 500))
}

// Code 通过 error 获取 code 定义
func Code(err error) int {
	code, ok := errs[err]
	if !ok {
		for err != nil {
			err = errors.Unwrap(err)
			code, ok = errs[err]
			if ok {
				return code
			}
		}
		code = Unknown
	}
	return code
}

func main() {
	// generate a response with a status code via error
	fn.SetErrorEncoder(func(ctx context.Context, err error) interface{} {
		code := Code(err)
		return map[string]interface{}{
			"code":    code,
			"message": err.Error(),
		}
	})
	router := mux.NewRouter()
	router.Handle("/error1", fn.Wrap(Error1))
	router.Handle("/error2", fn.Wrap(Error2))
	router.Handle("/error3", fn.Wrap(Error3))
	server := &http.Server{
		Addr:    ":8080",
		Handler: router,
	}
	server.ListenAndServe()
}

run server

go run main.go

test response

$ curl -i http://127.0.0.1:8080/error1
HTTP/1.1 500 Internal Server Error
Content-Type: application/json; charset=utf-8
Date: Thu, 27 Feb 2020 09:39:56 GMT
Content-Length: 31

{"code":1000,"message":"test"}

$ curl -i http://127.0.0.1:8080/error2
HTTP/1.1 500 Internal Server Error
Content-Type: application/json; charset=utf-8
Date: Thu, 27 Feb 2020 09:40:04 GMT
Content-Length: 31

{"code":1001,"message":"test"}

$curl -i http://127.0.0.1:8080/error3
HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Date: Thu, 27 Feb 2020 09:40:11 GMT
Content-Length: 31

{"code":1001,"message":"test"}

If possible I can submit a merge request to fix these issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions