diff --git a/binding/binding.go b/binding/binding.go index 3a2aad9c..30f36b99 100644 --- a/binding/binding.go +++ b/binding/binding.go @@ -18,6 +18,7 @@ const ( MIMEPROTOBUF = "application/x-protobuf" MIMEMSGPACK = "application/x-msgpack" MIMEMSGPACK2 = "application/msgpack" + MIMEYAML = "application/x-yaml" ) // Binding describes the interface which needs to be implemented for binding the @@ -68,6 +69,7 @@ var ( FormMultipart = formMultipartBinding{} ProtoBuf = protobufBinding{} MsgPack = msgpackBinding{} + YAML = yamlBinding{} ) // Default returns the appropriate Binding instance based on the HTTP method @@ -86,6 +88,8 @@ func Default(method, contentType string) Binding { return ProtoBuf case MIMEMSGPACK, MIMEMSGPACK2: return MsgPack + case MIMEYAML: + return YAML default: //case MIMEPOSTForm, MIMEMultipartPOSTForm: return Form } diff --git a/binding/binding_body_test.go b/binding/binding_body_test.go index dfd761e1..901d429c 100644 --- a/binding/binding_body_test.go +++ b/binding/binding_body_test.go @@ -19,12 +19,12 @@ func TestBindingBody(t *testing.T) { want string }{ { - name: "JSON bidning", + name: "JSON binding", binding: JSON, body: `{"foo":"FOO"}`, }, { - name: "XML bidning", + name: "XML binding", binding: XML, body: ` @@ -36,6 +36,11 @@ func TestBindingBody(t *testing.T) { binding: MsgPack, body: msgPackBody(t), }, + { + name: "YAML binding", + binding: YAML, + body: `foo: FOO`, + }, } { t.Logf("testing: %s", tt.name) req := requestWithBody("POST", "/", tt.body) diff --git a/binding/binding_test.go b/binding/binding_test.go index efe87669..e76cb853 100644 --- a/binding/binding_test.go +++ b/binding/binding_test.go @@ -190,6 +190,9 @@ func TestBindingDefault(t *testing.T) { assert.Equal(t, MsgPack, Default("POST", MIMEMSGPACK)) assert.Equal(t, MsgPack, Default("PUT", MIMEMSGPACK2)) + + assert.Equal(t, YAML, Default("POST", MIMEYAML)) + assert.Equal(t, YAML, Default("PUT", MIMEYAML)) } func TestBindingJSON(t *testing.T) { @@ -473,6 +476,20 @@ func TestBindingXMLFail(t *testing.T) { "bar", "foo") } +func TestBindingYAML(t *testing.T) { + testBodyBinding(t, + YAML, "yaml", + "/", "/", + `foo: bar`, `bar: foo`) +} + +func TestBindingYAMLFail(t *testing.T) { + testBodyBindingFail(t, + YAML, "yaml", + "/", "/", + `foo:\nbar`, `bar: foo`) +} + func createFormPostRequest() *http.Request { req, _ := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar&bar=foo")) req.Header.Set("Content-Type", MIMEPOSTForm) diff --git a/binding/yaml.go b/binding/yaml.go new file mode 100644 index 00000000..545c1038 --- /dev/null +++ b/binding/yaml.go @@ -0,0 +1,35 @@ +// 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 binding + +import ( + "bytes" + "io" + "net/http" + + "gopkg.in/yaml.v2" +) + +type yamlBinding struct{} + +func (yamlBinding) Name() string { + return "yaml" +} + +func (yamlBinding) Bind(req *http.Request, obj interface{}) error { + return decodeYAML(req.Body, obj) +} + +func (yamlBinding) BindBody(body []byte, obj interface{}) error { + return decodeYAML(bytes.NewReader(body), obj) +} + +func decodeYAML(r io.Reader, obj interface{}) error { + decoder := yaml.NewDecoder(r) + if err := decoder.Decode(obj); err != nil { + return err + } + return validate(obj) +}