mirror of https://github.com/gofiber/fiber.git
🔥 Add function to override form decoder setting (#1100)
* 🔥 add function to overide form decoder setting 🔥 Feature : SetBodyParserDecoder map all option to form decoder, use with BodyParserConfig, BodyParserType 🚨 Test : Test_Ctx_BodyParser_WithSetBodyParserDecoder * 🔥 Use decoder builder function with default setting on init decoderPoolpull/1556/head
parent
26c29e248f
commit
35e38db771
43
ctx.go
43
ctx.go
|
@ -86,6 +86,21 @@ type Views interface {
|
|||
Render(io.Writer, string, interface{}, ...string) error
|
||||
}
|
||||
|
||||
// BodyParserType require two element, type and converter for register.
|
||||
// Use BodyParserType with BodyParser for parsing custom type in form data.
|
||||
type BodyParserType struct {
|
||||
Customtype interface{}
|
||||
Converter func(string) reflect.Value
|
||||
}
|
||||
|
||||
// BodyParserConfig form decoder config for SetBodyParserDecoder
|
||||
type BodyParserConfig struct {
|
||||
IgnoreUnknownKeys bool
|
||||
SetAliasTag string
|
||||
BodyParserType []BodyParserType
|
||||
ZeroEmpty bool
|
||||
}
|
||||
|
||||
// AcquireCtx retrieves a new Ctx from the pool.
|
||||
func (app *App) AcquireCtx(fctx *fasthttp.RequestCtx) *Ctx {
|
||||
c := app.pool.Get().(*Ctx)
|
||||
|
@ -272,12 +287,32 @@ func (c *Ctx) Body() []byte {
|
|||
|
||||
// decoderPool helps to improve BodyParser's and QueryParser's performance
|
||||
var decoderPool = &sync.Pool{New: func() interface{} {
|
||||
var decoder = schema.NewDecoder()
|
||||
decoder.ZeroEmpty(true)
|
||||
decoder.IgnoreUnknownKeys(true)
|
||||
return decoder
|
||||
return decoderBuilder(BodyParserConfig{
|
||||
IgnoreUnknownKeys: true,
|
||||
ZeroEmpty: true,
|
||||
})
|
||||
}}
|
||||
|
||||
// SetBodyParserDecoder allow globally change the option of form decoder, update decoderPool
|
||||
func SetBodyParserDecoder(bodyParserConfig BodyParserConfig) {
|
||||
decoderPool = &sync.Pool{New: func() interface{} {
|
||||
return decoderBuilder(bodyParserConfig)
|
||||
}}
|
||||
}
|
||||
|
||||
func decoderBuilder(bodyParserConfig BodyParserConfig) interface{} {
|
||||
var decoder = schema.NewDecoder()
|
||||
decoder.IgnoreUnknownKeys(bodyParserConfig.IgnoreUnknownKeys)
|
||||
if bodyParserConfig.SetAliasTag != "" {
|
||||
decoder.SetAliasTag(bodyParserConfig.SetAliasTag)
|
||||
}
|
||||
for _, v := range bodyParserConfig.BodyParserType {
|
||||
decoder.RegisterConverter(reflect.ValueOf(v.Customtype).Interface(), v.Converter)
|
||||
}
|
||||
decoder.ZeroEmpty(bodyParserConfig.ZeroEmpty)
|
||||
return decoder
|
||||
}
|
||||
|
||||
// BodyParser binds the request body to a struct.
|
||||
// It supports decoding the following content types based on the Content-Type header:
|
||||
// application/json, application/xml, application/x-www-form-urlencoded, multipart/form-data
|
||||
|
|
54
ctx_test.go
54
ctx_test.go
|
@ -399,6 +399,60 @@ func Test_Ctx_BodyParser(t *testing.T) {
|
|||
testDecodeParserError(MIMEMultipartForm+`;boundary="b"`, "--b")
|
||||
}
|
||||
|
||||
// go test -run Test_Ctx_BodyParser_WithSetBodyParserDecoder
|
||||
func Test_Ctx_BodyParser_WithSetBodyParserDecoder(t *testing.T) {
|
||||
type CustomTime time.Time
|
||||
|
||||
var timeConverter = func(value string) reflect.Value {
|
||||
if v, err := time.Parse("2006-01-02", value); err == nil {
|
||||
return reflect.ValueOf(v)
|
||||
}
|
||||
return reflect.Value{}
|
||||
}
|
||||
|
||||
customTime := BodyParserType{
|
||||
Customtype: CustomTime{},
|
||||
Converter: timeConverter,
|
||||
}
|
||||
|
||||
SetBodyParserDecoder(BodyParserConfig{
|
||||
IgnoreUnknownKeys: true,
|
||||
BodyParserType: []BodyParserType{customTime},
|
||||
ZeroEmpty: true,
|
||||
SetAliasTag: "form",
|
||||
})
|
||||
|
||||
t.Parallel()
|
||||
app := New()
|
||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
defer app.ReleaseCtx(c)
|
||||
|
||||
type Demo struct {
|
||||
Date CustomTime `form:"date"`
|
||||
Title string `form:"title"`
|
||||
Body string `form:"body"`
|
||||
}
|
||||
|
||||
testDecodeParser := func(contentType, body string) {
|
||||
c.Request().Header.SetContentType(contentType)
|
||||
c.Request().SetBody([]byte(body))
|
||||
c.Request().Header.SetContentLength(len(body))
|
||||
d := Demo{
|
||||
Title: "Existing title",
|
||||
Body: "Existing Body",
|
||||
}
|
||||
utils.AssertEqual(t, nil, c.BodyParser(&d))
|
||||
date := fmt.Sprintf("%v", d.Date)
|
||||
fmt.Println(date, d.Title, d.Body)
|
||||
utils.AssertEqual(t, "{0 63743587200 <nil>}", date)
|
||||
utils.AssertEqual(t, "", d.Title)
|
||||
utils.AssertEqual(t, "New Body", d.Body)
|
||||
}
|
||||
|
||||
testDecodeParser(MIMEApplicationForm, "date=2020-12-15&title=&body=New Body")
|
||||
testDecodeParser(MIMEMultipartForm+`; boundary="b"`, "--b\r\nContent-Disposition: form-data; name=\"date\"\r\n\r\n2020-12-15\r\n--b\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\n\r\n--b\r\nContent-Disposition: form-data; name=\"body\"\r\n\r\nNew Body\r\n--b--")
|
||||
}
|
||||
|
||||
// go test -v -run=^$ -bench=Benchmark_Ctx_BodyParser_JSON -benchmem -count=4
|
||||
func Benchmark_Ctx_BodyParser_JSON(b *testing.B) {
|
||||
app := New()
|
||||
|
|
Loading…
Reference in New Issue