github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/net/http/httperror/httperror.go (about)

     1  // Package httperror defines the format for HTTP error responses
     2  // from Chain services.
     3  package httperror
     4  
     5  import (
     6  	"context"
     7  	"net/http"
     8  
     9  	"github.com/bytom/bytom/errors"
    10  	"github.com/bytom/bytom/net/http/httpjson"
    11  )
    12  
    13  // Info contains a set of error codes to send to the user.
    14  type Info struct {
    15  	HTTPStatus int    `json:"-"`
    16  	ChainCode  string `json:"code"`
    17  	Message    string `json:"msg"`
    18  }
    19  
    20  // Response defines the error response for a Chain error.
    21  type Response struct {
    22  	Info
    23  	Status    string                 `json:"status,omitempty"`
    24  	Detail    string                 `json:"detail,omitempty"`
    25  	Data      map[string]interface{} `json:"data,omitempty"`
    26  	Temporary bool                   `json:"temporary"`
    27  }
    28  
    29  // Formatter defines rules for mapping errors to the Chain error
    30  // response format.
    31  type Formatter struct {
    32  	Default     Info
    33  	IsTemporary func(info Info, err error) bool
    34  	Errors      map[error]Info
    35  }
    36  
    37  // Format builds an error Response body describing err by consulting
    38  // the f.Errors lookup table. If no entry is found, it returns f.Default.
    39  func (f Formatter) Format(err error) (body Response) {
    40  	root := errors.Root(err)
    41  	// Some types cannot be used as map keys, for example slices.
    42  	// If an error's underlying type is one of these, don't panic.
    43  	// Just treat it like any other missing entry.
    44  	defer func() {
    45  		if err := recover(); err != nil {
    46  			body = Response{f.Default, "fail", "", nil, true}
    47  		}
    48  	}()
    49  	info, ok := f.Errors[root]
    50  	if !ok {
    51  		info = f.Default
    52  	}
    53  
    54  	body = Response{
    55  		Info:      info,
    56  		Status:    "fail",
    57  		Detail:    errors.Detail(err),
    58  		Data:      errors.Data(err),
    59  		Temporary: f.IsTemporary(info, err),
    60  	}
    61  	return body
    62  }
    63  
    64  // Write writes a json encoded Response to the ResponseWriter.
    65  // It uses the status code associated with the error.
    66  //
    67  // Write may be used as an ErrorWriter in the httpjson package.
    68  func (f Formatter) Write(ctx context.Context, w http.ResponseWriter, err error) {
    69  	resp := f.Format(err)
    70  	httpjson.Write(ctx, w, resp.HTTPStatus, resp)
    71  }