This commit is contained in:
p8bin 2024-10-28 09:31:44 +03:00 committed by GitHub
commit 4c9845fd80
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 299 additions and 0 deletions

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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"
)

View File

@ -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
}

View File

@ -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])
}