github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/api/util/errors.go (about) 1 package util 2 3 import ( 4 "errors" 5 "fmt" 6 "net/http" 7 "reflect" 8 "strings" 9 10 golog "github.com/ipfs/go-log" 11 "github.com/qri-io/qfs" 12 "github.com/qri-io/qri/dsref" 13 "github.com/qri-io/qri/repo" 14 ) 15 16 var log = golog.Logger("qriapiutil") 17 18 // APIError is an error that specifies its http status code 19 type APIError struct { 20 Code int 21 Message string 22 } 23 24 // NewAPIError returns a new APIError 25 func NewAPIError(code int, message string) *APIError { 26 return &APIError{Code: code, Message: message} 27 } 28 29 // Error renders the APIError as a string 30 func (err *APIError) Error() string { 31 return err.Message 32 } 33 34 // RespondWithError writes the error, with meaningful text, to the http response 35 func RespondWithError(w http.ResponseWriter, err error) { 36 if errors.Is(err, dsref.ErrRefNotFound) || errors.Is(err, qfs.ErrNotFound) { 37 WriteErrResponse(w, http.StatusNotFound, err) 38 return 39 } 40 if errors.Is(err, repo.ErrNotFound) { 41 WriteErrResponse(w, http.StatusNotFound, err) 42 return 43 } 44 if errors.Is(err, repo.ErrNoHistory) { 45 WriteErrResponse(w, http.StatusUnprocessableEntity, err) 46 return 47 } 48 if errors.Is(err, dsref.ErrBadCaseShouldRename) || errors.Is(err, dsref.ErrDescribeValidName) || errors.Is(err, dsref.ErrDescribeValidUsername) { 49 WriteErrResponse(w, http.StatusBadRequest, err) 50 return 51 } 52 var perr *dsref.ParseError 53 if errors.As(err, &perr) { 54 WriteErrResponse(w, http.StatusBadRequest, err) 55 return 56 } 57 var aerr *APIError 58 if errors.As(err, &aerr) { 59 WriteErrResponse(w, aerr.Code, err) 60 return 61 } 62 if strings.HasPrefix(err.Error(), "invalid selection path: ") { 63 // This error comes from `pathValue` in base/select.go 64 WriteErrResponse(w, http.StatusBadRequest, err) 65 return 66 } 67 if strings.HasPrefix(err.Error(), "error loading dataset: error getting file bytes") { 68 WriteErrResponse(w, http.StatusNotFound, err) 69 return 70 } 71 log.Errorf("%s: treating this as a 500 is a bug, see https://github.com/qri-io/qri/issues/959. The code path that generated this should return a known error type, which this function should map to a reasonable http status code", err) 72 WriteErrResponse(w, http.StatusInternalServerError, err) 73 return 74 } 75 76 // RespondWithDispatchTypeError writes an error describing a type mismatch error from using dispatch 77 func RespondWithDispatchTypeError(w http.ResponseWriter, got interface{}) { 78 log.Errorf("type mismatch: %v of type %s", got, reflect.TypeOf(got)) 79 WriteErrResponse(w, http.StatusInternalServerError, fmt.Errorf("type mismatch: %v of type %s", got, reflect.TypeOf(got))) 80 }