forked from mirror/gin
Fixing new errors API
This commit is contained in:
parent
306da81aaf
commit
37b6f6c179
28
context.go
28
context.go
|
@ -126,7 +126,7 @@ func (c *Context) AbortWithStatus(code int) {
|
|||
c.Abort()
|
||||
}
|
||||
|
||||
func (c *Context) AbortWithError(code int, err error) *errorMsg {
|
||||
func (c *Context) AbortWithError(code int, err error) *Error {
|
||||
c.AbortWithStatus(code)
|
||||
return c.Error(err)
|
||||
}
|
||||
|
@ -142,21 +142,19 @@ func (c *Context) IsAborted() bool {
|
|||
// Attaches an error to the current context. The error is pushed to a list of errors.
|
||||
// It's a good idea to call Error for each error that occurred during the resolution of a request.
|
||||
// A middleware can be used to collect all the errors and push them to a database together, print a log, or append it in the HTTP response.
|
||||
func (c *Context) Error(err error) *errorMsg {
|
||||
newError := &errorMsg{
|
||||
func (c *Context) Error(err error) *Error {
|
||||
var parsedError *Error
|
||||
switch err.(type) {
|
||||
case *Error:
|
||||
parsedError = err.(*Error)
|
||||
default:
|
||||
parsedError = &Error{
|
||||
Err: err,
|
||||
Flags: ErrorTypePrivate,
|
||||
Type: ErrorTypePrivate,
|
||||
}
|
||||
c.Errors = append(c.Errors, newError)
|
||||
return newError
|
||||
}
|
||||
|
||||
func (c *Context) LastError() error {
|
||||
nuErrors := len(c.Errors)
|
||||
if nuErrors > 0 {
|
||||
return c.Errors[nuErrors-1].Err
|
||||
}
|
||||
return nil
|
||||
c.Errors = append(c.Errors, parsedError)
|
||||
return parsedError
|
||||
}
|
||||
|
||||
/************************************/
|
||||
|
@ -270,7 +268,7 @@ func (c *Context) BindJSON(obj interface{}) error {
|
|||
|
||||
func (c *Context) BindWith(obj interface{}, b binding.Binding) error {
|
||||
if err := b.Bind(c.Request, obj); err != nil {
|
||||
c.AbortWithError(400, err).Type(ErrorTypeBind)
|
||||
c.AbortWithError(400, err).SetType(ErrorTypeBind)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -309,7 +307,7 @@ func (c *Context) Render(code int, r render.Render) {
|
|||
c.Writer.WriteHeader(code)
|
||||
if err := r.Write(c.Writer); err != nil {
|
||||
debugPrintError(err)
|
||||
c.AbortWithError(500, err).Type(ErrorTypeRender)
|
||||
c.AbortWithError(500, err).SetType(ErrorTypeRender)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -349,56 +349,50 @@ func TestContextAbortWithStatus(t *testing.T) {
|
|||
|
||||
func TestContextError(t *testing.T) {
|
||||
c, _, _ := createTestContext()
|
||||
assert.Nil(t, c.LastError())
|
||||
assert.Empty(t, c.Errors.String())
|
||||
assert.Empty(t, c.Errors)
|
||||
|
||||
c.Error(errors.New("first error")).Meta("some data")
|
||||
assert.Equal(t, c.LastError().Error(), "first error")
|
||||
c.Error(errors.New("first error"))
|
||||
assert.Len(t, c.Errors, 1)
|
||||
assert.Equal(t, c.Errors.String(), "Error #01: first error\n Meta: some data\n")
|
||||
assert.Equal(t, c.Errors.String(), "Error #01: first error\n")
|
||||
|
||||
c.Error(errors.New("second error")).Meta("some data 2")
|
||||
assert.Equal(t, c.LastError().Error(), "second error")
|
||||
c.Error(&Error{
|
||||
Err: errors.New("second error"),
|
||||
Meta: "some data 2",
|
||||
Type: ErrorTypePublic,
|
||||
})
|
||||
assert.Len(t, c.Errors, 2)
|
||||
assert.Equal(t, c.Errors.String(), "Error #01: first error\n Meta: some data\n"+
|
||||
"Error #02: second error\n Meta: some data 2\n")
|
||||
|
||||
assert.Equal(t, c.Errors[0].Err, errors.New("first error"))
|
||||
assert.Equal(t, c.Errors[0].Metadata, "some data")
|
||||
assert.Equal(t, c.Errors[0].Flags, ErrorTypePrivate)
|
||||
assert.Nil(t, c.Errors[0].Meta)
|
||||
assert.Equal(t, c.Errors[0].Type, ErrorTypePrivate)
|
||||
|
||||
assert.Equal(t, c.Errors[1].Err, errors.New("second error"))
|
||||
assert.Equal(t, c.Errors[1].Metadata, "some data 2")
|
||||
assert.Equal(t, c.Errors[1].Flags, ErrorTypePrivate)
|
||||
assert.Equal(t, c.Errors[1].Meta, "some data 2")
|
||||
assert.Equal(t, c.Errors[1].Type, ErrorTypePublic)
|
||||
|
||||
assert.Equal(t, c.Errors.Last(), c.Errors[1])
|
||||
}
|
||||
|
||||
func TestContextTypedError(t *testing.T) {
|
||||
c, _, _ := createTestContext()
|
||||
c.Error(errors.New("externo 0")).Type(ErrorTypePublic)
|
||||
c.Error(errors.New("externo 1")).Type(ErrorTypePublic)
|
||||
c.Error(errors.New("interno 0")).Type(ErrorTypePrivate)
|
||||
c.Error(errors.New("externo 2")).Type(ErrorTypePublic)
|
||||
c.Error(errors.New("interno 1")).Type(ErrorTypePrivate)
|
||||
c.Error(errors.New("interno 2")).Type(ErrorTypePrivate)
|
||||
c.Error(errors.New("externo 0")).SetType(ErrorTypePublic)
|
||||
c.Error(errors.New("interno 0")).SetType(ErrorTypePrivate)
|
||||
|
||||
for _, err := range c.Errors.ByType(ErrorTypePublic) {
|
||||
assert.Equal(t, err.Flags, ErrorTypePublic)
|
||||
assert.Equal(t, err.Type, ErrorTypePublic)
|
||||
}
|
||||
|
||||
for _, err := range c.Errors.ByType(ErrorTypePrivate) {
|
||||
assert.Equal(t, err.Flags, ErrorTypePrivate)
|
||||
assert.Equal(t, err.Type, ErrorTypePrivate)
|
||||
}
|
||||
assert.Equal(t, c.Errors.Errors(), []string{"externo 0", "interno 0"})
|
||||
}
|
||||
|
||||
assert.Equal(t, c.Errors.Errors(), []string{"externo 0", "externo 1", "interno 0", "externo 2", "interno 1", "interno 2"})
|
||||
}
|
||||
|
||||
func TestContextFail(t *testing.T) {
|
||||
func TestContextAbortWithError(t *testing.T) {
|
||||
c, w, _ := createTestContext()
|
||||
c.AbortWithError(401, errors.New("bad input"))
|
||||
c.AbortWithError(401, errors.New("bad input")).SetMeta("some input")
|
||||
c.Writer.WriteHeaderNow()
|
||||
|
||||
assert.Equal(t, w.Code, 401)
|
||||
assert.Equal(t, c.LastError().Error(), "bad input")
|
||||
assert.Equal(t, c.index, AbortIndex)
|
||||
assert.True(t, c.IsAborted())
|
||||
}
|
||||
|
|
39
errors.go
39
errors.go
|
@ -21,33 +21,37 @@ const (
|
|||
)
|
||||
|
||||
// Used internally to collect errors that occurred during an http request.
|
||||
type errorMsg struct {
|
||||
type Error struct {
|
||||
Err error `json:"error"`
|
||||
Flags int `json:"-"`
|
||||
Metadata interface{} `json:"meta"`
|
||||
Type int `json:"-"`
|
||||
Meta interface{} `json:"meta"`
|
||||
}
|
||||
|
||||
func (msg *errorMsg) Type(flags int) *errorMsg {
|
||||
msg.Flags = flags
|
||||
var _ error = &Error{}
|
||||
|
||||
func (msg *Error) SetType(flags int) *Error {
|
||||
msg.Type = flags
|
||||
return msg
|
||||
}
|
||||
|
||||
func (msg *errorMsg) Meta(data interface{}) *errorMsg {
|
||||
msg.Metadata = data
|
||||
func (msg *Error) SetMeta(data interface{}) *Error {
|
||||
msg.Meta = data
|
||||
return msg
|
||||
}
|
||||
|
||||
func (msg *errorMsg) JSON() interface{} {
|
||||
func (msg *Error) JSON() interface{} {
|
||||
json := H{}
|
||||
if msg.Metadata != nil {
|
||||
value := reflect.ValueOf(msg.Metadata)
|
||||
if msg.Meta != nil {
|
||||
value := reflect.ValueOf(msg.Meta)
|
||||
switch value.Kind() {
|
||||
case reflect.Struct:
|
||||
return msg.Metadata
|
||||
return msg.Meta
|
||||
case reflect.Map:
|
||||
for _, key := range value.MapKeys() {
|
||||
json[key.String()] = value.MapIndex(key).Interface()
|
||||
}
|
||||
default:
|
||||
json["meta"] = msg.Meta
|
||||
}
|
||||
}
|
||||
if _, ok := json["error"]; !ok {
|
||||
|
@ -56,11 +60,11 @@ func (msg *errorMsg) JSON() interface{} {
|
|||
return json
|
||||
}
|
||||
|
||||
func (msg *errorMsg) Error() string {
|
||||
func (msg *Error) Error() string {
|
||||
return msg.Err.Error()
|
||||
}
|
||||
|
||||
type errorMsgs []*errorMsg
|
||||
type errorMsgs []*Error
|
||||
|
||||
func (a errorMsgs) ByType(typ int) errorMsgs {
|
||||
if len(a) == 0 {
|
||||
|
@ -68,14 +72,14 @@ func (a errorMsgs) ByType(typ int) errorMsgs {
|
|||
}
|
||||
result := make(errorMsgs, 0, len(a))
|
||||
for _, msg := range a {
|
||||
if msg.Flags&typ > 0 {
|
||||
if msg.Type&typ > 0 {
|
||||
result = append(result, msg)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (a errorMsgs) Last() *errorMsg {
|
||||
func (a errorMsgs) Last() *Error {
|
||||
length := len(a)
|
||||
if length == 0 {
|
||||
return nil
|
||||
|
@ -115,7 +119,10 @@ func (a errorMsgs) String() string {
|
|||
}
|
||||
var buffer bytes.Buffer
|
||||
for i, msg := range a {
|
||||
fmt.Fprintf(&buffer, "Error #%02d: %s\n Meta: %v\n", (i + 1), msg.Err, msg.Metadata)
|
||||
fmt.Fprintf(&buffer, "Error #%02d: %s\n", (i + 1), msg.Err)
|
||||
if msg.Meta != nil {
|
||||
fmt.Fprintf(&buffer, " Meta: %v\n", msg.Meta)
|
||||
}
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright 2014 Manu Martinez-Almeida. All rights reserved.
|
||||
// Use of this source code is governed by a MIT style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
baseError := errors.New("test error")
|
||||
err := &Error{
|
||||
Err: baseError,
|
||||
Type: ErrorTypePrivate,
|
||||
}
|
||||
assert.Equal(t, err.Error(), baseError.Error())
|
||||
assert.Equal(t, err.JSON(), H{"error": baseError.Error()})
|
||||
|
||||
assert.Equal(t, err.SetType(ErrorTypePublic), err)
|
||||
assert.Equal(t, err.Type, ErrorTypePublic)
|
||||
|
||||
assert.Equal(t, err.SetMeta("some data"), err)
|
||||
assert.Equal(t, err.Meta, "some data")
|
||||
assert.Equal(t, err.JSON(), H{
|
||||
"error": baseError.Error(),
|
||||
"meta": "some data",
|
||||
})
|
||||
|
||||
err.SetMeta(H{
|
||||
"status": "200",
|
||||
"data": "some data",
|
||||
})
|
||||
assert.Equal(t, err.JSON(), H{
|
||||
"error": baseError.Error(),
|
||||
"status": "200",
|
||||
"data": "some data",
|
||||
})
|
||||
|
||||
err.SetMeta(H{
|
||||
"error": "custom error",
|
||||
"status": "200",
|
||||
"data": "some data",
|
||||
})
|
||||
assert.Equal(t, err.JSON(), H{
|
||||
"error": "custom error",
|
||||
"status": "200",
|
||||
"data": "some data",
|
||||
})
|
||||
}
|
||||
|
||||
func TestErrorSlice(t *testing.T) {
|
||||
errs := errorMsgs{
|
||||
{Err: errors.New("first"), Type: ErrorTypePrivate},
|
||||
{Err: errors.New("second"), Type: ErrorTypePrivate, Meta: "some data"},
|
||||
{Err: errors.New("third"), Type: ErrorTypePublic, Meta: H{"status": "400"}},
|
||||
}
|
||||
|
||||
assert.Equal(t, errs.Last().Error(), "third")
|
||||
assert.Equal(t, errs.Errors(), []string{"first", "second", "third"})
|
||||
assert.Equal(t, errs.ByType(ErrorTypePublic).Errors(), []string{"third"})
|
||||
assert.Equal(t, errs.ByType(ErrorTypePrivate).Errors(), []string{"first", "second"})
|
||||
assert.Equal(t, errs.ByType(ErrorTypePublic|ErrorTypePrivate).Errors(), []string{"first", "second", "third"})
|
||||
assert.Empty(t, errs.ByType(ErrorTypeBind))
|
||||
|
||||
assert.Equal(t, errs.String(), `Error #01: first
|
||||
Error #02: second
|
||||
Meta: some data
|
||||
Error #03: third
|
||||
Meta: map[status:400]
|
||||
`)
|
||||
assert.Equal(t, errs.JSON(), []interface{}{
|
||||
H{"error": "first"},
|
||||
H{"error": "second", "meta": "some data"},
|
||||
H{"error": "third", "status": "400"},
|
||||
})
|
||||
|
||||
errs = errorMsgs{
|
||||
{Err: errors.New("first"), Type: ErrorTypePrivate},
|
||||
}
|
||||
assert.Equal(t, errs.JSON(), H{"error": "first"})
|
||||
|
||||
errs = errorMsgs{}
|
||||
assert.Nil(t, errs.Last())
|
||||
assert.Nil(t, errs.JSON())
|
||||
assert.Empty(t, errs.String())
|
||||
}
|
Loading…
Reference in New Issue