From 706b2a814358bdb5a3c8dd3ce934a7732719343b Mon Sep 17 00:00:00 2001 From: Gordon Tyler Date: Wed, 31 Oct 2018 14:36:22 -0400 Subject: [PATCH] Add YAML binding methods to Context. --- README.md | 6 +++--- context.go | 11 +++++++++++ context_test.go | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ce413325..36fe8d20 100644 --- a/README.md +++ b/README.md @@ -529,7 +529,7 @@ func main() { ### Model binding and validation -To bind a request body into a type, use model binding. We currently support binding of JSON, XML and standard form values (foo=bar&boo=baz). +To bind a request body into a type, use model binding. We currently support binding of JSON, XML, YAML and standard form values (foo=bar&boo=baz). Gin uses [**go-playground/validator.v8**](https://github.com/go-playground/validator) for validation. Check the full docs on tags usage [here](http://godoc.org/gopkg.in/go-playground/validator.v8#hdr-Baked_In_Validators_and_Tags). @@ -537,10 +537,10 @@ Note that you need to set the corresponding binding tag on all fields you want t Also, Gin provides two sets of methods for binding: - **Type** - Must bind - - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery` + - **Methods** - `Bind`, `BindJSON`, `BindXML`, `BindQuery`, `BindYAML` - **Behavior** - These methods use `MustBindWith` under the hood. If there is a binding error, the request is aborted with `c.AbortWithError(400, err).SetType(ErrorTypeBind)`. This sets the response status code to 400 and the `Content-Type` header is set to `text/plain; charset=utf-8`. Note that if you try to set the response code after this, it will result in a warning `[GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422`. If you wish to have greater control over the behavior, consider using the `ShouldBind` equivalent method. - **Type** - Should bind - - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery` + - **Methods** - `ShouldBind`, `ShouldBindJSON`, `ShouldBindXML`, `ShouldBindQuery`, `ShouldBindYAML` - **Behavior** - These methods use `ShouldBindWith` under the hood. If there is a binding error, the error is returned and it is the developer's responsibility to handle the request and error appropriately. When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use `MustBindWith` or `ShouldBindWith`. diff --git a/context.go b/context.go index c8a59bb0..89693d0c 100644 --- a/context.go +++ b/context.go @@ -32,6 +32,7 @@ const ( MIMEPOSTForm = binding.MIMEPOSTForm MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm BodyBytesKey = "_gin-gonic/gin/bodybyteskey" + MIMEYAML = binding.MIMEYAML ) const abortIndex int8 = math.MaxInt8 / 2 @@ -524,6 +525,11 @@ func (c *Context) BindQuery(obj interface{}) error { return c.MustBindWith(obj, binding.Query) } +// BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML). +func (c *Context) BindYAML(obj interface{}) error { + return c.MustBindWith(obj, binding.YAML) +} + // MustBindWith binds the passed struct pointer using the specified binding engine. // It will abort the request with HTTP 400 if any error ocurrs. // See the binding package. @@ -563,6 +569,11 @@ func (c *Context) ShouldBindQuery(obj interface{}) error { return c.ShouldBindWith(obj, binding.Query) } +// ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML). +func (c *Context) ShouldBindYAML(obj interface{}) error { + return c.ShouldBindWith(obj, binding.YAML) +} + // ShouldBindWith binds the passed struct pointer using the specified binding engine. // See the binding package. func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error { diff --git a/context_test.go b/context_test.go index fb492e02..dced73fd 100644 --- a/context_test.go +++ b/context_test.go @@ -1380,6 +1380,23 @@ func TestContextBindWithQuery(t *testing.T) { assert.Equal(t, 0, w.Body.Len()) } +func TestContextBindWithYAML(t *testing.T) { + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + + c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo: bar\nbar: foo")) + c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type + + var obj struct { + Foo string `yaml:"foo"` + Bar string `yaml:"bar"` + } + assert.NoError(t, c.BindYAML(&obj)) + assert.Equal(t, "foo", obj.Bar) + assert.Equal(t, "bar", obj.Foo) + assert.Equal(t, 0, w.Body.Len()) +} + func TestContextBadAutoBind(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w) @@ -1470,6 +1487,23 @@ func TestContextShouldBindWithQuery(t *testing.T) { assert.Equal(t, 0, w.Body.Len()) } +func TestContextShouldBindWithYAML(t *testing.T) { + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + + c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo: bar\nbar: foo")) + c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type + + var obj struct { + Foo string `yaml:"foo"` + Bar string `yaml:"bar"` + } + assert.NoError(t, c.ShouldBindYAML(&obj)) + assert.Equal(t, "foo", obj.Bar) + assert.Equal(t, "bar", obj.Foo) + assert.Equal(t, 0, w.Body.Len()) +} + func TestContextBadAutoShouldBind(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w)