diff --git a/errors/gerror/gerror.go b/errors/gerror/gerror.go index b961be831..29e14bb14 100644 --- a/errors/gerror/gerror.go +++ b/errors/gerror/gerror.go @@ -142,10 +142,14 @@ func WrapSkipf(skip int, err error, format string, args ...interface{}) error { } // NewCode creates and returns an error that has error code and given text. -func NewCode(code int, text string) error { +func NewCode(code int, text ...string) error { + errText := "" + if len(text) > 0 { + errText = text[0] + } return &Error{ stack: callers(), - text: text, + text: errText, code: code, } } @@ -238,14 +242,24 @@ func WrapCodeSkipf(code, skip int, err error, format string, args ...interface{} } // Code returns the error code of current error. -// It returns -1 if it has no error code or it does not implements interface Code. +// It returns CodeNil if it has no error code or it does not implements interface Code. func Code(err error) int { if err != nil { if e, ok := err.(apiCode); ok { return e.Code() } } - return -1 + return CodeNil +} + +// CodeMessage retrieves and returns the error code message from given error. +func CodeMessage(err error) string { + return Message(Code(err)) +} + +// Message returns the message string for specified code. +func Message(code int) string { + return codeMessageMap[code] } // Cause returns the root cause error of . diff --git a/errors/gerror/gerror_code.go b/errors/gerror/gerror_code.go index 055ea0ab0..c0eecc0f4 100644 --- a/errors/gerror/gerror_code.go +++ b/errors/gerror/gerror_code.go @@ -9,32 +9,60 @@ package gerror // Reserved internal error code of framework: code < 1000. const ( - // =============================================================================== - // Common system codes. - // =============================================================================== - - CodeNil = -1 // No error code specified. - CodeOk = 0 // It is OK. - CodeInternalError = 50 + iota // An error occurred internally. - CodeValidationFailed // Data validation failed. - CodeDbOperationError // Database operation error. - CodeInvalidParameter // The given parameter for current operation is invalid. - CodeMissingParameter // Parameter for current operation is missing. - CodeInvalidOperation // The function cannot be used like this. - CodeInvalidConfiguration // The configuration is invalid for current operation. - CodeMissingConfiguration // The configuration is missing for current operation. - CodeNotImplemented // The operation is not implemented yet. - CodeNotSupported // The operation is not supported yet. - CodeOperationFailed // I tried, but I cannot give you what you want. - CodeNotAuthorized // Not Authorized. - CodeSecurityReason // Security Reason. - CodeServerBusy // Server is busy, please try again later. - CodeUnknown // Unknown error. - CodeResourceNotExist // Resource does not exist. - - // =============================================================================== - // Common business codes. - // =============================================================================== - - CodeBusinessValidationFailed = 300 + iota // Business validation failed. + CodeNil = -1 // No error code specified. + CodeOk = 0 // It is OK. + CodeInternalError = 50 // An error occurred internally. + CodeValidationFailed = 51 // Data validation failed. + CodeDbOperationError = 52 // Database operation error. + CodeInvalidParameter = 53 // The given parameter for current operation is invalid. + CodeMissingParameter = 54 // Parameter for current operation is missing. + CodeInvalidOperation = 55 // The function cannot be used like this. + CodeInvalidConfiguration = 56 // The configuration is invalid for current operation. + CodeMissingConfiguration = 57 // The configuration is missing for current operation. + CodeNotImplemented = 58 // The operation is not implemented yet. + CodeNotSupported = 59 // The operation is not supported yet. + CodeOperationFailed = 60 // I tried, but I cannot give you what you want. + CodeNotAuthorized = 61 // Not Authorized. + CodeSecurityReason = 62 // Security Reason. + CodeServerBusy = 63 // Server is busy, please try again later. + CodeUnknown = 64 // Unknown error. + CodeResourceNotExist = 65 // Resource does not exist. + CodeBusinessValidationFailed = 300 // Business validation failed. ) + +var ( + // codeMessageMap is the mapping from code to according string message. + codeMessageMap = map[int]string{ + CodeNil: "", + CodeOk: "OK", + CodeInternalError: "Internal Error", + CodeValidationFailed: "Validation Failed", + CodeDbOperationError: "Database Operation Error", + CodeInvalidParameter: "Invalid Parameter", + CodeMissingParameter: "Missing Parameter", + CodeInvalidOperation: "Invalid Operation", + CodeInvalidConfiguration: "Invalid Configuration", + CodeMissingConfiguration: "Missing Configuration", + CodeNotImplemented: "Not Implemented", + CodeNotSupported: "Not Supported", + CodeOperationFailed: "Operation Failed", + CodeNotAuthorized: "Not Authorized", + CodeSecurityReason: "Security Reason", + CodeServerBusy: "Server Is Busy", + CodeUnknown: "Unknown Error", + CodeResourceNotExist: "Resource Not Exist", + CodeBusinessValidationFailed: "Business Validation Failed", + } +) + +// RegisterCode registers custom error code to global error codes for gerror recognition. +func RegisterCode(code int, message string) { + codeMessageMap[code] = message +} + +// RegisterCodeMap registers custom error codes to global error codes for gerror recognition using map. +func RegisterCodeMap(codes map[int]string) { + for k, v := range codes { + codeMessageMap[k] = v + } +} diff --git a/errors/gerror/gerror_error.go b/errors/gerror/gerror_error.go index 045385d84..f0953f7ce 100644 --- a/errors/gerror/gerror_error.go +++ b/errors/gerror/gerror_error.go @@ -57,10 +57,10 @@ func (err *Error) Error() string { } // Code returns the error code. -// It returns -1 if it has no error code. +// It returns CodeNil if it has no error code. func (err *Error) Code() int { if err == nil { - return -1 + return CodeNil } return err.code } @@ -159,6 +159,7 @@ func (err *Error) Current() error { error: nil, stack: err.stack, text: err.text, + code: err.code, } } diff --git a/errors/gerror/gerror_z_unit_test.go b/errors/gerror/gerror_z_unit_test.go index e60243aa7..0bffed596 100644 --- a/errors/gerror/gerror_z_unit_test.go +++ b/errors/gerror/gerror_z_unit_test.go @@ -261,8 +261,8 @@ func Test_Code(t *testing.T) { t.Assert(err.Error(), "123") }) gtest.C(t, func(t *gtest.T) { - err := gerror.NewCode(1, "123") - t.Assert(gerror.Code(err), 1) + err := gerror.NewCode(gerror.CodeUnknown, "123") + t.Assert(gerror.Code(err), gerror.CodeUnknown) t.Assert(err.Error(), "123") }) gtest.C(t, func(t *gtest.T) { @@ -318,3 +318,36 @@ func Test_Json(t *testing.T) { t.Assert(string(b), `"2: 1"`) }) } + +func Test_Message(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + t.Assert(gerror.Message(-100), ``) + t.Assert(gerror.Message(gerror.CodeNil), ``) + t.Assert(gerror.Message(gerror.CodeOk), `OK`) + }) +} + +func Test_CodeMessage(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + err := gerror.NewCode(gerror.CodeUnknown) + t.Assert(gerror.CodeMessage(err), `Unknown Error`) + }) +} + +func Test_RegisterCode(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + gerror.RegisterCode(10086, "MobileTelecom") + t.Assert(gerror.Message(10086), `MobileTelecom`) + }) +} + +func Test_RegisterCodeMap(t *testing.T) { + gtest.C(t, func(t *gtest.T) { + gerror.RegisterCodeMap(map[int]string{ + 10087: "MobileTelecom 10087", + 10088: "MobileTelecom 10088", + }) + t.Assert(gerror.Message(10087), `MobileTelecom 10087`) + t.Assert(gerror.Message(10088), `MobileTelecom 10088`) + }) +} diff --git a/net/ghttp/ghttp_middleware_handler_response.go b/net/ghttp/ghttp_middleware_handler_response.go index f8c71c318..892ac796b 100644 --- a/net/ghttp/ghttp_middleware_handler_response.go +++ b/net/ghttp/ghttp_middleware_handler_response.go @@ -31,9 +31,13 @@ func MiddlewareHandlerResponse(r *Request) { if code == gerror.CodeNil { code = gerror.CodeInternalError } + message := err.Error() + if message == "" { + message = gerror.Message(code) + } internalErr = r.Response.WriteJson(DefaultHandlerResponse{ Code: code, - Message: err.Error(), + Message: message, Data: nil, }) if internalErr != nil { diff --git a/net/ghttp/ghttp_response_write.go b/net/ghttp/ghttp_response_write.go index f8aca67a6..c7dbd10f8 100644 --- a/net/ghttp/ghttp_response_write.go +++ b/net/ghttp/ghttp_response_write.go @@ -71,7 +71,7 @@ func (r *Response) WritefExit(format string, params ...interface{}) { r.Request.Exit() } -// Writef writes the response with and new line. +// Writeln writes the response with and new line. func (r *Response) Writeln(content ...interface{}) { if len(content) == 0 { r.Write("\n") diff --git a/net/ghttp/ghttp_unit_router_handler_extended_test.go b/net/ghttp/ghttp_unit_router_handler_extended_test.go index 49f00095c..77d50c8f2 100644 --- a/net/ghttp/ghttp_unit_router_handler_extended_test.go +++ b/net/ghttp/ghttp_unit_router_handler_extended_test.go @@ -77,6 +77,6 @@ func Test_Router_Handler_Extended_Handler_WithObject(t *testing.T) { client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p)) t.Assert(client.GetContent("/test?age=18&name=john"), `{"code":0,"message":"","data":{"Id":1,"Age":18,"Name":"john"}}`) - t.Assert(client.GetContent("/test/error"), `{"code":52,"message":"error","data":null}`) + t.Assert(client.GetContent("/test/error"), `{"code":50,"message":"error","data":null}`) }) } diff --git a/util/gconv/gconv.go b/util/gconv/gconv.go index 77e492fe8..0a72171f8 100644 --- a/util/gconv/gconv.go +++ b/util/gconv/gconv.go @@ -53,7 +53,7 @@ type doConvertInput struct { Extra []interface{} // Extra values for implementing the converting. } -// doConvert does common used types converting. +// doConvert does commonly used types converting. func doConvert(input doConvertInput) interface{} { switch input.ToTypeName { case "int": @@ -366,7 +366,7 @@ func Runes(any interface{}) []rune { } // String converts `any` to string. -// It's most common used converting function. +// It's most commonly used converting function. func String(any interface{}) string { if any == nil { return "" @@ -459,7 +459,7 @@ func String(any interface{}) string { if kind == reflect.Ptr { return String(rv.Elem().Interface()) } - // Finally we use json.Marshal to convert. + // Finally, we use json.Marshal to convert. if jsonContent, err := json.Marshal(value); err != nil { return fmt.Sprint(value) } else {