mirror of https://github.com/gin-gonic/gin.git
Merge 8e66616db7
into ea53388e6e
This commit is contained in:
commit
4c9845fd80
|
@ -0,0 +1,18 @@
|
||||||
|
package errorparser
|
||||||
|
|
||||||
|
func ParseBindError(err error) (errs []ParseError, match bool) {
|
||||||
|
|
||||||
|
if errs, ok := parseValidatorError(err); ok {
|
||||||
|
return errs, true
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs, ok := parseJsonDecodeError(err); ok {
|
||||||
|
return errs, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: protobuf
|
||||||
|
// todo: xml
|
||||||
|
// todo: yaml
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package errorparser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseBindError(t *testing.T) {
|
||||||
|
|
||||||
|
_, ok := ParseBindError(fmt.Errorf("not match"))
|
||||||
|
assert.False(t, ok)
|
||||||
|
|
||||||
|
_, ok = ParseBindError(validator.ValidationErrors([]validator.FieldError{}))
|
||||||
|
assert.True(t, ok)
|
||||||
|
|
||||||
|
_, ok = ParseBindError(&json.SyntaxError{})
|
||||||
|
assert.True(t, ok)
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package errorparser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseJsonDecodeError(err error) (errs []ParseError, match bool) {
|
||||||
|
|
||||||
|
if typeErr, ok := err.(*json.UnmarshalTypeError); ok {
|
||||||
|
return parseJsonUnmarshalTypeError(typeErr), true
|
||||||
|
}
|
||||||
|
|
||||||
|
if syntaxErr, ok := err.(*json.SyntaxError); ok {
|
||||||
|
return parseJsonSyntaxError(syntaxErr), true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseJsonUnmarshalTypeError(err *json.UnmarshalTypeError) (errs []ParseError) {
|
||||||
|
|
||||||
|
errs = []ParseError{}
|
||||||
|
|
||||||
|
item := NewParseError(
|
||||||
|
err.Field,
|
||||||
|
ParseErrorTypeMismatch,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, item)
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseJsonSyntaxError(err *json.SyntaxError) (errs []ParseError) {
|
||||||
|
|
||||||
|
errs = []ParseError{}
|
||||||
|
|
||||||
|
item := NewParseError(
|
||||||
|
"",
|
||||||
|
ParseErrorTypeBadInput,
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, item)
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package errorparser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseJsonDecodeError(t *testing.T) {
|
||||||
|
|
||||||
|
_, ok := parseJsonDecodeError(fmt.Errorf("not match"))
|
||||||
|
assert.False(t, ok)
|
||||||
|
|
||||||
|
_, ok = parseJsonDecodeError(&json.UnmarshalTypeError{})
|
||||||
|
assert.True(t, ok)
|
||||||
|
|
||||||
|
_, ok = parseJsonDecodeError(&json.SyntaxError{})
|
||||||
|
assert.True(t, ok)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseJsonUnmarshalTypeError(t *testing.T) {
|
||||||
|
|
||||||
|
jsonData := `{
|
||||||
|
"text": "text",
|
||||||
|
"count": "1"
|
||||||
|
}`
|
||||||
|
|
||||||
|
rbody := bytes.NewReader([]byte(jsonData))
|
||||||
|
|
||||||
|
c, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||||
|
c.Request, _ = http.NewRequest("POST", "/", rbody)
|
||||||
|
c.Request.Header.Add("Content-Type", gin.MIMEJSON)
|
||||||
|
|
||||||
|
var obj struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.Bind(&obj)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
typeErr, ok := err.(*json.UnmarshalTypeError)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
parseErrs := parseJsonUnmarshalTypeError(typeErr)
|
||||||
|
require.Equal(t, len(parseErrs), 1)
|
||||||
|
|
||||||
|
assert.Equal(t, parseErrs[0].ParamName, "count")
|
||||||
|
assert.Equal(t, parseErrs[0].ErrorType, ParseErrorTypeMismatch)
|
||||||
|
assert.Equal(t, parseErrs[0].InitialError, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseJsonSyntaxError(t *testing.T) {
|
||||||
|
|
||||||
|
jsonData := `{
|
||||||
|
"text": "text"
|
||||||
|
"count": 1
|
||||||
|
}`
|
||||||
|
|
||||||
|
rbody := bytes.NewReader([]byte(jsonData))
|
||||||
|
|
||||||
|
c, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||||
|
c.Request, _ = http.NewRequest("POST", "/", rbody)
|
||||||
|
c.Request.Header.Add("Content-Type", gin.MIMEJSON)
|
||||||
|
|
||||||
|
var obj struct {
|
||||||
|
Text string `json:"text"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.Bind(&obj)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
typeErr, ok := err.(*json.SyntaxError)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
parseErrs := parseJsonSyntaxError(typeErr)
|
||||||
|
require.Equal(t, len(parseErrs), 1)
|
||||||
|
|
||||||
|
assert.Equal(t, parseErrs[0].ParamName, "")
|
||||||
|
assert.Equal(t, parseErrs[0].ErrorType, ParseErrorTypeBadInput)
|
||||||
|
assert.Equal(t, parseErrs[0].InitialError, err)
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package errorparser
|
||||||
|
|
||||||
|
type ParseError struct {
|
||||||
|
ParamName string
|
||||||
|
ErrorType ParseErrorType
|
||||||
|
InitialError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewParseError(
|
||||||
|
paramName string,
|
||||||
|
errorType ParseErrorType,
|
||||||
|
initialError error,
|
||||||
|
) ParseError {
|
||||||
|
return ParseError{
|
||||||
|
ParamName: paramName,
|
||||||
|
ErrorType: errorType,
|
||||||
|
InitialError: initialError,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParseErrorType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ParseErrorTypeNone ParseErrorType = ""
|
||||||
|
ParseErrorTypeBadInput ParseErrorType = "bad_input"
|
||||||
|
ParseErrorTypeMismatch ParseErrorType = "type_mismatch"
|
||||||
|
ParseErrorTypeValidation ParseErrorType = "validation"
|
||||||
|
)
|
|
@ -0,0 +1,27 @@
|
||||||
|
package errorparser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseValidatorError(err error) (errs []ParseError, match bool) {
|
||||||
|
if vErr, ok := err.(validator.ValidationErrors); ok {
|
||||||
|
return parseValidatorValidationErrors(vErr), true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseValidatorValidationErrors(vErr validator.ValidationErrors) (errs []ParseError) {
|
||||||
|
fErrs := []validator.FieldError(vErr)
|
||||||
|
errs = make([]ParseError, 0, len(fErrs))
|
||||||
|
for _, fErr := range fErrs {
|
||||||
|
item := NewParseError(
|
||||||
|
fErr.Field(),
|
||||||
|
ParseErrorTypeValidation,
|
||||||
|
fErr,
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, item)
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package errorparser
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseValidatorError(t *testing.T) {
|
||||||
|
|
||||||
|
_, ok := parseValidatorError(fmt.Errorf("not match"))
|
||||||
|
assert.False(t, ok)
|
||||||
|
|
||||||
|
_, ok = parseValidatorError(validator.ValidationErrors{})
|
||||||
|
assert.True(t, ok)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseValidatorValidationErrors(t *testing.T) {
|
||||||
|
|
||||||
|
jsonData := `{
|
||||||
|
"text": "",
|
||||||
|
"count": 1
|
||||||
|
}`
|
||||||
|
|
||||||
|
rbody := bytes.NewReader([]byte(jsonData))
|
||||||
|
|
||||||
|
c, _ := gin.CreateTestContext(httptest.NewRecorder())
|
||||||
|
c.Request, _ = http.NewRequest("POST", "/", rbody)
|
||||||
|
c.Request.Header.Add("Content-Type", gin.MIMEJSON)
|
||||||
|
|
||||||
|
var obj struct {
|
||||||
|
Text string `json:"text" binding:"required"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.Bind(&obj)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
vErr, ok := err.(validator.ValidationErrors)
|
||||||
|
require.True(t, ok)
|
||||||
|
|
||||||
|
fErrs := []validator.FieldError(vErr)
|
||||||
|
require.Equal(t, len(fErrs), 1)
|
||||||
|
|
||||||
|
parseErrs := parseValidatorValidationErrors(vErr)
|
||||||
|
require.Equal(t, len(parseErrs), 1)
|
||||||
|
|
||||||
|
assert.Equal(t, parseErrs[0].ParamName, fErrs[0].Field())
|
||||||
|
assert.Equal(t, parseErrs[0].ErrorType, ParseErrorTypeValidation)
|
||||||
|
assert.Equal(t, parseErrs[0].InitialError, fErrs[0])
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue