From ab83acceba9e1026199230f42d34218fcce5af6d Mon Sep 17 00:00:00 2001 From: Kai-Chu Chung Date: Wed, 11 Apr 2018 14:23:23 +0800 Subject: [PATCH] feat(Error): add Google JSON style error response (#4) implement error response with Google JSON style format --- ctx.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ ctx_test.go | 18 ++++++------------ gerr.go | 21 +++++++++++++++++++++ proto.go | 35 ----------------------------------- 4 files changed, 74 insertions(+), 47 deletions(-) create mode 100644 gerr.go delete mode 100644 proto.go diff --git a/ctx.go b/ctx.go index fb216aa..3b2c74d 100644 --- a/ctx.go +++ b/ctx.go @@ -2,6 +2,8 @@ package ctx import ( "encoding/json" + "fmt" + "strconv" "strings" "github.com/labstack/echo" @@ -131,3 +133,48 @@ func (r *errorCall) Do() (err error) { } return r.c.JSONBlob(r.httpStatus, b) } + +// Google JSON Style error call +type gerrorCall struct { + c echo.Context + httpStatus int + responseParams GErrorResponse +} + +type gerrorMessage struct { + Code int `json:"code"` + Message string `json:"message"` + Errors []GError `json:"errors,omitempty"` +} + +type GErrorResponse struct { + ApiVersion string `json:"apiVersion"` + Error gerrorMessage `json:"error"` +} + +func (c CustomCtx) GError(errs ...GError) *gerrorCall { + rs := &gerrorCall{ + c: echo.Context(c), + responseParams: GErrorResponse{ + ApiVersion: apiVersion, + Error: gerrorMessage{}, + }, + } + + if len(errs) > 0 { + s, _ := strconv.Atoi(fmt.Sprintf("%d", errs[0].Code)[:3]) + rs.httpStatus = s + rs.responseParams.Error.Code = errs[0].Code + rs.responseParams.Error.Message = errs[0].Message + rs.responseParams.Error.Errors = errs + } + return rs +} + +func (r *gerrorCall) Do() (err error) { + b, err := json.Marshal(r.responseParams) + if err != nil { + return err + } + return r.c.JSONBlob(r.httpStatus, b) +} diff --git a/ctx_test.go b/ctx_test.go index 8ae1e60..129d3a1 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -29,11 +29,8 @@ func TestCustomCtx(t *testing.T) { name: "400 with google json style", givenHandler: func(c echo.Context) error { - errCode := 40000001 - - errData := ctx.NewErrorProto() - - errData.Add(ctx.ErrorProtoItem{ + gerr := ctx.NewGErrors().Append(ctx.GError{ + Code: 40000001, Domain: "Calendar", Reason: "ResourceNotFoundException", Message: "Resources is not exist", @@ -41,11 +38,8 @@ func TestCustomCtx(t *testing.T) { Location: "query", ExtendedHelp: "http://help-link", SendReport: "http://report.dajui.com/", - }) - - errMsg := errData.Items[0].Message - - errData.Add(ctx.ErrorProtoItem{ + }).Append(ctx.GError{ + Code: 40000001, Domain: "global", Reason: "required", Message: "Required parameter: part", @@ -53,9 +47,9 @@ func TestCustomCtx(t *testing.T) { Location: "part", }) - return c.(ctx.CustomCtx).Resp(errCode).Error(fmt.Sprintf("%v", errMsg)).Code(errCode).Errors(errData.AsErrors()).Do() + return c.(ctx.CustomCtx).GError(gerr...).Do() }, - wantJSON: `{"apiVersion":"1.0","error":{"code":40000001,"message":"Resources is not exist","errors":[{"extended_help":"http://help-link", "send_report":"http://report.dajui.com/", "domain":"Calendar", "reason":"ResourceNotFoundException", "message":"Resources is not exist", "location":"query", "location_type":"database query"},{"message":"Required parameter: part", "location":"part", "location_type":"parameter", "domain":"global", "reason":"required"}]}}`, + wantJSON: `{"apiVersion":"1.0","error":{"code":40000001,"message":"Resources is not exist","errors":[{"extendedHelp":"http://help-link", "sendReport":"http://report.dajui.com/", "domain":"Calendar", "reason":"ResourceNotFoundException", "message":"Resources is not exist", "location":"query", "locationType":"database query"},{"message":"Required parameter: part", "location":"part", "locationType":"parameter", "domain":"global", "reason":"required"}]}}`, }, { name: "400 with string errors", diff --git a/gerr.go b/gerr.go new file mode 100644 index 0000000..69448ba --- /dev/null +++ b/gerr.go @@ -0,0 +1,21 @@ +package ctx + +type GErrors []GError + +type GError struct { + Code int `json:"-"` + Domain string `json:"domain,omitempty"` + Reason string `json:"reason,omitempty"` + Message string `json:"message,omitempty"` + Location string `json:"location,omitempty"` + LocationType string `json:"locationType,omitempty"` + ExtendedHelp string `json:"extendedHelp,omitempty"` + SendReport string `json:"sendReport,omitempty"` +} + +func (c GErrors) Append(gerr GError) GErrors { + c = append(c, gerr) + return c +} + +func NewGErrors() GErrors { return GErrors{} } diff --git a/proto.go b/proto.go deleted file mode 100644 index 163e91e..0000000 --- a/proto.go +++ /dev/null @@ -1,35 +0,0 @@ -package ctx - -type ErrorProto struct { - Items []ErrorProtoItem -} - -type ErrorProtoItem struct { - Domain string `json:"domain,omitempty"` - Reason string `json:"reason,omitempty"` - Message string `json:"message,omitempty"` - Location string `json:"location,omitempty"` - LocationType string `json:"location_type,omitempty"` - ExtendedHelp string `json:"extended_help,omitempty"` - SendReport string `json:"send_report,omitempty"` -} - -func NewErrorProto() *ErrorProto { return &ErrorProto{} } - -func NewErrorProtoItem() *ErrorProtoItem { return &ErrorProtoItem{} } - -func (e *ErrorProto) Add(d ErrorProtoItem) *ErrorProto { - - e.Items = append(e.Items, d) - - return e -} - -func (e *ErrorProto) AsErrors() []interface{} { - - errs := make([]interface{}, len(e.Items)) - for i, v := range e.Items { - errs[i] = v - } - return errs -}