mirror of https://github.com/gin-gonic/gin.git
binding/render: modular deps
This commit is contained in:
parent
ffcbe77b1e
commit
54eda7fe73
|
@ -4,110 +4,70 @@
|
||||||
|
|
||||||
package binding
|
package binding
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
// Content-Type MIME of the most common data formats.
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
const (
|
|
||||||
MIMEJSON = "application/json"
|
|
||||||
MIMEHTML = "text/html"
|
|
||||||
MIMEXML = "application/xml"
|
|
||||||
MIMEXML2 = "text/xml"
|
|
||||||
MIMEPlain = "text/plain"
|
|
||||||
MIMEPOSTForm = "application/x-www-form-urlencoded"
|
|
||||||
MIMEMultipartPOSTForm = "multipart/form-data"
|
|
||||||
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
|
|
||||||
// data present in the request such as JSON request body, query parameters or
|
|
||||||
// the form POST.
|
|
||||||
type Binding interface {
|
|
||||||
Name() string
|
|
||||||
Bind(*http.Request, interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
|
|
||||||
// but it reads the body from supplied bytes instead of req.Body.
|
|
||||||
type BindingBody interface {
|
|
||||||
Binding
|
|
||||||
BindBody([]byte, interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
|
||||||
// but it read the Params.
|
|
||||||
type BindingUri interface {
|
|
||||||
Name() string
|
|
||||||
BindUri(map[string][]string, interface{}) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// StructValidator is the minimal interface which needs to be implemented in
|
|
||||||
// order for it to be used as the validator engine for ensuring the correctness
|
|
||||||
// of the request. Gin provides a default implementation for this using
|
|
||||||
// https://github.com/go-playground/validator/tree/v8.18.2.
|
|
||||||
type StructValidator interface {
|
|
||||||
// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
|
|
||||||
// If the received type is not a struct, any validation should be skipped and nil must be returned.
|
|
||||||
// If the received type is a struct or pointer to a struct, the validation should be performed.
|
|
||||||
// If the struct is not valid or the validation itself fails, a descriptive error should be returned.
|
|
||||||
// Otherwise nil must be returned.
|
|
||||||
ValidateStruct(interface{}) error
|
|
||||||
|
|
||||||
// Engine returns the underlying validator engine which powers the
|
|
||||||
// StructValidator implementation.
|
|
||||||
Engine() interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validator is the default validator which implements the StructValidator
|
|
||||||
// interface. It uses https://github.com/go-playground/validator/tree/v8.18.2
|
|
||||||
// under the hood.
|
|
||||||
var Validator StructValidator = &defaultValidator{}
|
|
||||||
|
|
||||||
// These implement the Binding interface and can be used to bind the data
|
// These implement the Binding interface and can be used to bind the data
|
||||||
// present in the request to struct instances.
|
// present in the request to struct instances.
|
||||||
var (
|
var (
|
||||||
JSON = jsonBinding{}
|
|
||||||
XML = xmlBinding{}
|
|
||||||
Form = formBinding{}
|
Form = formBinding{}
|
||||||
Query = queryBinding{}
|
Query = queryBinding{}
|
||||||
FormPost = formPostBinding{}
|
FormPost = formPostBinding{}
|
||||||
FormMultipart = formMultipartBinding{}
|
|
||||||
ProtoBuf = protobufBinding{}
|
|
||||||
MsgPack = msgpackBinding{}
|
|
||||||
YAML = yamlBinding{}
|
|
||||||
Uri = uriBinding{}
|
Uri = uriBinding{}
|
||||||
|
FormMultipart = formMultipartBinding{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default returns the appropriate Binding instance based on the HTTP method
|
// Default returns the appropriate Binding instance based on the HTTP method
|
||||||
// and the content type.
|
// and the content type.
|
||||||
func Default(method, contentType string) Binding {
|
func Default(method, contentType string) common.Binding {
|
||||||
if method == "GET" {
|
if method == "GET" {
|
||||||
return Form
|
return Form
|
||||||
}
|
}
|
||||||
|
|
||||||
switch contentType {
|
switch contentType {
|
||||||
case MIMEJSON:
|
case common.MIMEMultipartPOSTForm:
|
||||||
return JSON
|
|
||||||
case MIMEXML, MIMEXML2:
|
|
||||||
return XML
|
|
||||||
case MIMEPROTOBUF:
|
|
||||||
return ProtoBuf
|
|
||||||
case MIMEMSGPACK, MIMEMSGPACK2:
|
|
||||||
return MsgPack
|
|
||||||
case MIMEYAML:
|
|
||||||
return YAML
|
|
||||||
case MIMEMultipartPOSTForm:
|
|
||||||
return FormMultipart
|
return FormMultipart
|
||||||
default: // case MIMEPOSTForm:
|
default:
|
||||||
return Form
|
b, ok := common.List[contentType]
|
||||||
|
if !ok {
|
||||||
|
return Form //Default to Form
|
||||||
|
}
|
||||||
|
return b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validate(obj interface{}) error {
|
//YAML return the binding for yaml if loaded
|
||||||
if Validator == nil {
|
func YAML() common.BindingBody {
|
||||||
return nil
|
return retBinding(common.MIMEYAML)
|
||||||
}
|
}
|
||||||
return Validator.ValidateStruct(obj)
|
|
||||||
|
//JSON return the binding for json if loaded
|
||||||
|
func JSON() common.BindingBody {
|
||||||
|
return retBinding(common.MIMEJSON)
|
||||||
|
}
|
||||||
|
|
||||||
|
//XML return the binding for xml if loaded
|
||||||
|
func XML() common.BindingBody {
|
||||||
|
return retBinding(common.MIMEXML)
|
||||||
|
}
|
||||||
|
|
||||||
|
//ProtoBuf return the binding for ProtoBuf if loaded
|
||||||
|
func ProtoBuf() common.BindingBody {
|
||||||
|
return retBinding(common.MIMEPROTOBUF)
|
||||||
|
}
|
||||||
|
|
||||||
|
//MsgPack return the binding for MsgPack if loaded
|
||||||
|
func MsgPack() common.BindingBody {
|
||||||
|
return retBinding(common.MIMEMSGPACK)
|
||||||
|
}
|
||||||
|
|
||||||
|
//retBinding Search for a render and panic on not found
|
||||||
|
func retBinding(contentType string) common.BindingBody {
|
||||||
|
b, ok := common.List[contentType]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("Undefined binding %s", contentType))
|
||||||
|
}
|
||||||
|
return b
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
"github.com/gin-gonic/gin/testdata/protoexample"
|
"github.com/gin-gonic/gin/testdata/protoexample"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -14,18 +15,18 @@ import (
|
||||||
func TestBindingBody(t *testing.T) {
|
func TestBindingBody(t *testing.T) {
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
name string
|
name string
|
||||||
binding BindingBody
|
binding common.BindingBody
|
||||||
body string
|
body string
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "JSON binding",
|
name: "JSON binding",
|
||||||
binding: JSON,
|
binding: JSON(),
|
||||||
body: `{"foo":"FOO"}`,
|
body: `{"foo":"FOO"}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "XML binding",
|
name: "XML binding",
|
||||||
binding: XML,
|
binding: XML(),
|
||||||
body: `<?xml version="1.0" encoding="UTF-8"?>
|
body: `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<root>
|
<root>
|
||||||
<foo>FOO</foo>
|
<foo>FOO</foo>
|
||||||
|
@ -33,12 +34,12 @@ func TestBindingBody(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "MsgPack binding",
|
name: "MsgPack binding",
|
||||||
binding: MsgPack,
|
binding: MsgPack(),
|
||||||
body: msgPackBody(t),
|
body: msgPackBody(t),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "YAML binding",
|
name: "YAML binding",
|
||||||
binding: YAML,
|
binding: YAML(),
|
||||||
body: `foo: FOO`,
|
body: `foo: FOO`,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
|
@ -67,6 +68,6 @@ func TestBindingBodyProto(t *testing.T) {
|
||||||
req := requestWithBody("POST", "/", string(data))
|
req := requestWithBody("POST", "/", string(data))
|
||||||
form := protoexample.Test{}
|
form := protoexample.Test{}
|
||||||
body, _ := ioutil.ReadAll(req.Body)
|
body, _ := ioutil.ReadAll(req.Body)
|
||||||
assert.NoError(t, ProtoBuf.BindBody(body, &form))
|
assert.NoError(t, ProtoBuf().BindBody(body, &form))
|
||||||
assert.Equal(t, test, form)
|
assert.Equal(t, test, form)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,17 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
"github.com/gin-gonic/gin/testdata/protoexample"
|
"github.com/gin-gonic/gin/testdata/protoexample"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/ugorji/go/codec"
|
"github.com/ugorji/go/codec"
|
||||||
|
|
||||||
|
_ "github.com/gin-gonic/gin/binding/json"
|
||||||
|
_ "github.com/gin-gonic/gin/binding/msgpack"
|
||||||
|
_ "github.com/gin-gonic/gin/binding/protobuf"
|
||||||
|
_ "github.com/gin-gonic/gin/binding/xml"
|
||||||
|
_ "github.com/gin-gonic/gin/binding/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FooStruct struct {
|
type FooStruct struct {
|
||||||
|
@ -190,54 +197,54 @@ type FooStructForMapPtrType struct {
|
||||||
|
|
||||||
func TestBindingDefault(t *testing.T) {
|
func TestBindingDefault(t *testing.T) {
|
||||||
assert.Equal(t, Form, Default("GET", ""))
|
assert.Equal(t, Form, Default("GET", ""))
|
||||||
assert.Equal(t, Form, Default("GET", MIMEJSON))
|
assert.Equal(t, Form, Default("GET", common.MIMEJSON))
|
||||||
|
|
||||||
assert.Equal(t, JSON, Default("POST", MIMEJSON))
|
assert.Equal(t, JSON(), Default("POST", common.MIMEJSON))
|
||||||
assert.Equal(t, JSON, Default("PUT", MIMEJSON))
|
assert.Equal(t, JSON(), Default("PUT", common.MIMEJSON))
|
||||||
|
|
||||||
assert.Equal(t, XML, Default("POST", MIMEXML))
|
assert.Equal(t, XML(), Default("POST", common.MIMEXML))
|
||||||
assert.Equal(t, XML, Default("PUT", MIMEXML2))
|
assert.Equal(t, XML(), Default("PUT", common.MIMEXML2))
|
||||||
|
|
||||||
assert.Equal(t, Form, Default("POST", MIMEPOSTForm))
|
assert.Equal(t, Form, Default("POST", common.MIMEPOSTForm))
|
||||||
assert.Equal(t, Form, Default("PUT", MIMEPOSTForm))
|
assert.Equal(t, Form, Default("PUT", common.MIMEPOSTForm))
|
||||||
|
|
||||||
assert.Equal(t, FormMultipart, Default("POST", MIMEMultipartPOSTForm))
|
assert.Equal(t, FormMultipart, Default("POST", common.MIMEMultipartPOSTForm))
|
||||||
assert.Equal(t, FormMultipart, Default("PUT", MIMEMultipartPOSTForm))
|
assert.Equal(t, FormMultipart, Default("PUT", common.MIMEMultipartPOSTForm))
|
||||||
|
|
||||||
assert.Equal(t, ProtoBuf, Default("POST", MIMEPROTOBUF))
|
assert.Equal(t, ProtoBuf(), Default("POST", common.MIMEPROTOBUF))
|
||||||
assert.Equal(t, ProtoBuf, Default("PUT", MIMEPROTOBUF))
|
assert.Equal(t, ProtoBuf(), Default("PUT", common.MIMEPROTOBUF))
|
||||||
|
|
||||||
assert.Equal(t, MsgPack, Default("POST", MIMEMSGPACK))
|
assert.Equal(t, MsgPack(), Default("POST", common.MIMEMSGPACK))
|
||||||
assert.Equal(t, MsgPack, Default("PUT", MIMEMSGPACK2))
|
assert.Equal(t, MsgPack(), Default("PUT", common.MIMEMSGPACK2))
|
||||||
|
|
||||||
assert.Equal(t, YAML, Default("POST", MIMEYAML))
|
assert.Equal(t, YAML(), Default("POST", common.MIMEYAML))
|
||||||
assert.Equal(t, YAML, Default("PUT", MIMEYAML))
|
assert.Equal(t, YAML(), Default("PUT", common.MIMEYAML))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBindingJSONNilBody(t *testing.T) {
|
func TestBindingJSONNilBody(t *testing.T) {
|
||||||
var obj FooStruct
|
var obj FooStruct
|
||||||
req, _ := http.NewRequest(http.MethodPost, "/", nil)
|
req, _ := http.NewRequest(http.MethodPost, "/", nil)
|
||||||
err := JSON.Bind(req, &obj)
|
err := JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBindingJSON(t *testing.T) {
|
func TestBindingJSON(t *testing.T) {
|
||||||
testBodyBinding(t,
|
testBodyBinding(t,
|
||||||
JSON, "json",
|
JSON(), "json",
|
||||||
"/", "/",
|
"/", "/",
|
||||||
`{"foo": "bar"}`, `{"bar": "foo"}`)
|
`{"foo": "bar"}`, `{"bar": "foo"}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBindingJSONUseNumber(t *testing.T) {
|
func TestBindingJSONUseNumber(t *testing.T) {
|
||||||
testBodyBindingUseNumber(t,
|
testBodyBindingUseNumber(t,
|
||||||
JSON, "json",
|
JSON(), "json",
|
||||||
"/", "/",
|
"/", "/",
|
||||||
`{"foo": 123}`, `{"bar": "foo"}`)
|
`{"foo": 123}`, `{"bar": "foo"}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBindingJSONUseNumber2(t *testing.T) {
|
func TestBindingJSONUseNumber2(t *testing.T) {
|
||||||
testBodyBindingUseNumber2(t,
|
testBodyBindingUseNumber2(t,
|
||||||
JSON, "json",
|
JSON(), "json",
|
||||||
"/", "/",
|
"/", "/",
|
||||||
`{"foo": 123}`, `{"bar": "foo"}`)
|
`{"foo": 123}`, `{"bar": "foo"}`)
|
||||||
}
|
}
|
||||||
|
@ -496,28 +503,28 @@ func TestBindingQueryBoolFail(t *testing.T) {
|
||||||
|
|
||||||
func TestBindingXML(t *testing.T) {
|
func TestBindingXML(t *testing.T) {
|
||||||
testBodyBinding(t,
|
testBodyBinding(t,
|
||||||
XML, "xml",
|
XML(), "xml",
|
||||||
"/", "/",
|
"/", "/",
|
||||||
"<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
|
"<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBindingXMLFail(t *testing.T) {
|
func TestBindingXMLFail(t *testing.T) {
|
||||||
testBodyBindingFail(t,
|
testBodyBindingFail(t,
|
||||||
XML, "xml",
|
XML(), "xml",
|
||||||
"/", "/",
|
"/", "/",
|
||||||
"<map><foo>bar<foo></map>", "<map><bar>foo</bar></map>")
|
"<map><foo>bar<foo></map>", "<map><bar>foo</bar></map>")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBindingYAML(t *testing.T) {
|
func TestBindingYAML(t *testing.T) {
|
||||||
testBodyBinding(t,
|
testBodyBinding(t,
|
||||||
YAML, "yaml",
|
YAML(), "yaml",
|
||||||
"/", "/",
|
"/", "/",
|
||||||
`foo: bar`, `bar: foo`)
|
`foo: bar`, `bar: foo`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBindingYAMLFail(t *testing.T) {
|
func TestBindingYAMLFail(t *testing.T) {
|
||||||
testBodyBindingFail(t,
|
testBodyBindingFail(t,
|
||||||
YAML, "yaml",
|
YAML(), "yaml",
|
||||||
"/", "/",
|
"/", "/",
|
||||||
`foo:\nbar`, `bar: foo`)
|
`foo:\nbar`, `bar: foo`)
|
||||||
}
|
}
|
||||||
|
@ -525,28 +532,28 @@ func TestBindingYAMLFail(t *testing.T) {
|
||||||
func createFormPostRequest(t *testing.T) *http.Request {
|
func createFormPostRequest(t *testing.T) *http.Request {
|
||||||
req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar&bar=foo"))
|
req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar&bar=foo"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", MIMEPOSTForm)
|
req.Header.Set("Content-Type", common.MIMEPOSTForm)
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
func createDefaultFormPostRequest(t *testing.T) *http.Request {
|
func createDefaultFormPostRequest(t *testing.T) *http.Request {
|
||||||
req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar"))
|
req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", MIMEPOSTForm)
|
req.Header.Set("Content-Type", common.MIMEPOSTForm)
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFormPostRequestForMap(t *testing.T) *http.Request {
|
func createFormPostRequestForMap(t *testing.T) *http.Request {
|
||||||
req, err := http.NewRequest("POST", "/?map_foo=getfoo", bytes.NewBufferString("map_foo={\"bar\":123}"))
|
req, err := http.NewRequest("POST", "/?map_foo=getfoo", bytes.NewBufferString("map_foo={\"bar\":123}"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", MIMEPOSTForm)
|
req.Header.Set("Content-Type", common.MIMEPOSTForm)
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
func createFormPostRequestForMapFail(t *testing.T) *http.Request {
|
func createFormPostRequestForMapFail(t *testing.T) *http.Request {
|
||||||
req, err := http.NewRequest("POST", "/?map_foo=getfoo", bytes.NewBufferString("map_foo=hello"))
|
req, err := http.NewRequest("POST", "/?map_foo=getfoo", bytes.NewBufferString("map_foo=hello"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", MIMEPOSTForm)
|
req.Header.Set("Content-Type", common.MIMEPOSTForm)
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,7 +576,7 @@ func createFormFilesMultipartRequest(t *testing.T) *http.Request {
|
||||||
|
|
||||||
req, err2 := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
|
req, err2 := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
|
||||||
assert.NoError(t, err2)
|
assert.NoError(t, err2)
|
||||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
req.Header.Set("Content-Type", common.MIMEMultipartPOSTForm+"; boundary="+boundary)
|
||||||
|
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
@ -593,7 +600,7 @@ func createFormFilesMultipartRequestFail(t *testing.T) *http.Request {
|
||||||
|
|
||||||
req, err2 := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
|
req, err2 := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
|
||||||
assert.NoError(t, err2)
|
assert.NoError(t, err2)
|
||||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
req.Header.Set("Content-Type", common.MIMEMultipartPOSTForm+"; boundary="+boundary)
|
||||||
|
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
@ -609,7 +616,7 @@ func createFormMultipartRequest(t *testing.T) *http.Request {
|
||||||
assert.NoError(t, mw.WriteField("bar", "foo"))
|
assert.NoError(t, mw.WriteField("bar", "foo"))
|
||||||
req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
|
req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
req.Header.Set("Content-Type", common.MIMEMultipartPOSTForm+"; boundary="+boundary)
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,7 +630,7 @@ func createFormMultipartRequestForMap(t *testing.T) *http.Request {
|
||||||
assert.NoError(t, mw.WriteField("map_foo", "{\"bar\":123, \"name\":\"thinkerou\", \"pai\": 3.14}"))
|
assert.NoError(t, mw.WriteField("map_foo", "{\"bar\":123, \"name\":\"thinkerou\", \"pai\": 3.14}"))
|
||||||
req, err := http.NewRequest("POST", "/?map_foo=getfoo", body)
|
req, err := http.NewRequest("POST", "/?map_foo=getfoo", body)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
req.Header.Set("Content-Type", common.MIMEMultipartPOSTForm+"; boundary="+boundary)
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -637,7 +644,7 @@ func createFormMultipartRequestForMapFail(t *testing.T) *http.Request {
|
||||||
assert.NoError(t, mw.WriteField("map_foo", "3.14"))
|
assert.NoError(t, mw.WriteField("map_foo", "3.14"))
|
||||||
req, err := http.NewRequest("POST", "/?map_foo=getfoo", body)
|
req, err := http.NewRequest("POST", "/?map_foo=getfoo", body)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
req.Header.Set("Content-Type", common.MIMEMultipartPOSTForm+"; boundary="+boundary)
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,7 +744,7 @@ func TestBindingProtoBuf(t *testing.T) {
|
||||||
data, _ := proto.Marshal(test)
|
data, _ := proto.Marshal(test)
|
||||||
|
|
||||||
testProtoBodyBinding(t,
|
testProtoBodyBinding(t,
|
||||||
ProtoBuf, "protobuf",
|
ProtoBuf(), "protobuf",
|
||||||
"/", "/",
|
"/", "/",
|
||||||
string(data), string(data[1:]))
|
string(data), string(data[1:]))
|
||||||
}
|
}
|
||||||
|
@ -749,7 +756,7 @@ func TestBindingProtoBufFail(t *testing.T) {
|
||||||
data, _ := proto.Marshal(test)
|
data, _ := proto.Marshal(test)
|
||||||
|
|
||||||
testProtoBodyBindingFail(t,
|
testProtoBodyBindingFail(t,
|
||||||
ProtoBuf, "protobuf",
|
ProtoBuf(), "protobuf",
|
||||||
"/", "/",
|
"/", "/",
|
||||||
string(data), string(data[1:]))
|
string(data), string(data[1:]))
|
||||||
}
|
}
|
||||||
|
@ -769,7 +776,7 @@ func TestBindingMsgPack(t *testing.T) {
|
||||||
data := buf.Bytes()
|
data := buf.Bytes()
|
||||||
|
|
||||||
testMsgPackBodyBinding(t,
|
testMsgPackBodyBinding(t,
|
||||||
MsgPack, "msgpack",
|
MsgPack(), "msgpack",
|
||||||
"/", "/",
|
"/", "/",
|
||||||
string(data), string(data[1:]))
|
string(data), string(data[1:]))
|
||||||
}
|
}
|
||||||
|
@ -777,18 +784,18 @@ func TestBindingMsgPack(t *testing.T) {
|
||||||
func TestValidationFails(t *testing.T) {
|
func TestValidationFails(t *testing.T) {
|
||||||
var obj FooStruct
|
var obj FooStruct
|
||||||
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
|
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
|
||||||
err := JSON.Bind(req, &obj)
|
err := JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidationDisabled(t *testing.T) {
|
func TestValidationDisabled(t *testing.T) {
|
||||||
backup := Validator
|
backup := common.Validator
|
||||||
Validator = nil
|
common.Validator = nil
|
||||||
defer func() { Validator = backup }()
|
defer func() { common.Validator = backup }()
|
||||||
|
|
||||||
var obj FooStruct
|
var obj FooStruct
|
||||||
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
|
req := requestWithBody("POST", "/", `{"bar": "foo"}`)
|
||||||
err := JSON.Bind(req, &obj)
|
err := JSON().Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -799,7 +806,7 @@ func TestExistsSucceeds(t *testing.T) {
|
||||||
|
|
||||||
var obj HogeStruct
|
var obj HogeStruct
|
||||||
req := requestWithBody("POST", "/", `{"hoge": 0}`)
|
req := requestWithBody("POST", "/", `{"hoge": 0}`)
|
||||||
err := JSON.Bind(req, &obj)
|
err := JSON().Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,7 +817,7 @@ func TestExistsFails(t *testing.T) {
|
||||||
|
|
||||||
var obj HogeStruct
|
var obj HogeStruct
|
||||||
req := requestWithBody("POST", "/", `{"boen": 0}`)
|
req := requestWithBody("POST", "/", `{"boen": 0}`)
|
||||||
err := JSON.Bind(req, &obj)
|
err := JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -864,7 +871,7 @@ func testFormBinding(t *testing.T, method, path, badPath, body, badBody string)
|
||||||
obj := FooBarStruct{}
|
obj := FooBarStruct{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -873,7 +880,7 @@ func testFormBinding(t *testing.T, method, path, badPath, body, badBody string)
|
||||||
|
|
||||||
obj = FooBarStruct{}
|
obj = FooBarStruct{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,7 +891,7 @@ func testFormBindingDefaultValue(t *testing.T, method, path, badPath, body, badB
|
||||||
obj := FooDefaultBarStruct{}
|
obj := FooDefaultBarStruct{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -893,7 +900,7 @@ func testFormBindingDefaultValue(t *testing.T, method, path, badPath, body, badB
|
||||||
|
|
||||||
obj = FooDefaultBarStruct{}
|
obj = FooDefaultBarStruct{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,7 +918,7 @@ func TestFormBindingMultipartFail(t *testing.T) {
|
||||||
obj := FooBarStruct{}
|
obj := FooBarStruct{}
|
||||||
req, err := http.NewRequest("POST", "/", strings.NewReader("foo=bar"))
|
req, err := http.NewRequest("POST", "/", strings.NewReader("foo=bar"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+";boundary=testboundary")
|
req.Header.Set("Content-Type", common.MIMEMultipartPOSTForm+";boundary=testboundary")
|
||||||
_, err = req.MultipartReader()
|
_, err = req.MultipartReader()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
err = Form.Bind(req, &obj)
|
err = Form.Bind(req, &obj)
|
||||||
|
@ -945,7 +952,7 @@ func testFormBindingForTime(t *testing.T, method, path, badPath, body, badBody s
|
||||||
obj := FooBarStructForTimeType{}
|
obj := FooBarStructForTimeType{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
|
|
||||||
|
@ -957,7 +964,7 @@ func testFormBindingForTime(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForTimeType{}
|
obj = FooBarStructForTimeType{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -968,14 +975,14 @@ func testFormBindingForTimeNotFormat(t *testing.T, method, path, badPath, body,
|
||||||
obj := FooStructForTimeTypeNotFormat{}
|
obj := FooStructForTimeTypeNotFormat{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
obj = FooStructForTimeTypeNotFormat{}
|
obj = FooStructForTimeTypeNotFormat{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -986,14 +993,14 @@ func testFormBindingForTimeFailFormat(t *testing.T, method, path, badPath, body,
|
||||||
obj := FooStructForTimeTypeFailFormat{}
|
obj := FooStructForTimeTypeFailFormat{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
obj = FooStructForTimeTypeFailFormat{}
|
obj = FooStructForTimeTypeFailFormat{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1004,14 +1011,14 @@ func testFormBindingForTimeFailLocation(t *testing.T, method, path, badPath, bod
|
||||||
obj := FooStructForTimeTypeFailLocation{}
|
obj := FooStructForTimeTypeFailLocation{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
obj = FooStructForTimeTypeFailLocation{}
|
obj = FooStructForTimeTypeFailLocation{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1022,7 +1029,7 @@ func testFormBindingIgnoreField(t *testing.T, method, path, badPath, body, badBo
|
||||||
obj := FooStructForIgnoreFormTag{}
|
obj := FooStructForIgnoreFormTag{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -1037,7 +1044,7 @@ func testFormBindingInvalidName(t *testing.T, method, path, badPath, body, badBo
|
||||||
obj := InvalidNameType{}
|
obj := InvalidNameType{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -1045,7 +1052,7 @@ func testFormBindingInvalidName(t *testing.T, method, path, badPath, body, badBo
|
||||||
|
|
||||||
obj = InvalidNameType{}
|
obj = InvalidNameType{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1056,14 +1063,14 @@ func testFormBindingInvalidName2(t *testing.T, method, path, badPath, body, badB
|
||||||
obj := InvalidNameMapType{}
|
obj := InvalidNameMapType{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
obj = InvalidNameMapType{}
|
obj = InvalidNameMapType{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1073,7 +1080,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
switch typ {
|
switch typ {
|
||||||
case "Int":
|
case "Int":
|
||||||
|
@ -1085,7 +1092,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForIntType{}
|
obj = FooBarStructForIntType{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Int8":
|
case "Int8":
|
||||||
obj := FooBarStructForInt8Type{}
|
obj := FooBarStructForInt8Type{}
|
||||||
|
@ -1096,7 +1103,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForInt8Type{}
|
obj = FooBarStructForInt8Type{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Int16":
|
case "Int16":
|
||||||
obj := FooBarStructForInt16Type{}
|
obj := FooBarStructForInt16Type{}
|
||||||
|
@ -1107,7 +1114,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForInt16Type{}
|
obj = FooBarStructForInt16Type{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Int32":
|
case "Int32":
|
||||||
obj := FooBarStructForInt32Type{}
|
obj := FooBarStructForInt32Type{}
|
||||||
|
@ -1118,7 +1125,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForInt32Type{}
|
obj = FooBarStructForInt32Type{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Int64":
|
case "Int64":
|
||||||
obj := FooBarStructForInt64Type{}
|
obj := FooBarStructForInt64Type{}
|
||||||
|
@ -1129,7 +1136,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForInt64Type{}
|
obj = FooBarStructForInt64Type{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Uint":
|
case "Uint":
|
||||||
obj := FooBarStructForUintType{}
|
obj := FooBarStructForUintType{}
|
||||||
|
@ -1140,7 +1147,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForUintType{}
|
obj = FooBarStructForUintType{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Uint8":
|
case "Uint8":
|
||||||
obj := FooBarStructForUint8Type{}
|
obj := FooBarStructForUint8Type{}
|
||||||
|
@ -1151,7 +1158,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForUint8Type{}
|
obj = FooBarStructForUint8Type{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Uint16":
|
case "Uint16":
|
||||||
obj := FooBarStructForUint16Type{}
|
obj := FooBarStructForUint16Type{}
|
||||||
|
@ -1162,7 +1169,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForUint16Type{}
|
obj = FooBarStructForUint16Type{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Uint32":
|
case "Uint32":
|
||||||
obj := FooBarStructForUint32Type{}
|
obj := FooBarStructForUint32Type{}
|
||||||
|
@ -1173,7 +1180,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForUint32Type{}
|
obj = FooBarStructForUint32Type{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Uint64":
|
case "Uint64":
|
||||||
obj := FooBarStructForUint64Type{}
|
obj := FooBarStructForUint64Type{}
|
||||||
|
@ -1184,7 +1191,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForUint64Type{}
|
obj = FooBarStructForUint64Type{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Float32":
|
case "Float32":
|
||||||
obj := FooBarStructForFloat32Type{}
|
obj := FooBarStructForFloat32Type{}
|
||||||
|
@ -1195,7 +1202,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForFloat32Type{}
|
obj = FooBarStructForFloat32Type{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Float64":
|
case "Float64":
|
||||||
obj := FooBarStructForFloat64Type{}
|
obj := FooBarStructForFloat64Type{}
|
||||||
|
@ -1206,7 +1213,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForFloat64Type{}
|
obj = FooBarStructForFloat64Type{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Bool":
|
case "Bool":
|
||||||
obj := FooBarStructForBoolType{}
|
obj := FooBarStructForBoolType{}
|
||||||
|
@ -1217,7 +1224,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooBarStructForBoolType{}
|
obj = FooBarStructForBoolType{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Slice":
|
case "Slice":
|
||||||
obj := FooStructForSliceType{}
|
obj := FooStructForSliceType{}
|
||||||
|
@ -1227,7 +1234,7 @@ func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody s
|
||||||
|
|
||||||
obj = FooStructForSliceType{}
|
obj = FooStructForSliceType{}
|
||||||
req = requestWithBody(method, badPath, badBody)
|
req = requestWithBody(method, badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
case "Struct":
|
case "Struct":
|
||||||
obj := FooStructForStructType{}
|
obj := FooStructForStructType{}
|
||||||
|
@ -1291,7 +1298,7 @@ func testQueryBinding(t *testing.T, method, path, badPath, body, badBody string)
|
||||||
obj := FooBarStruct{}
|
obj := FooBarStruct{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -1306,7 +1313,7 @@ func testQueryBindingFail(t *testing.T, method, path, badPath, body, badBody str
|
||||||
obj := FooStructForMapType{}
|
obj := FooStructForMapType{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
@ -1319,13 +1326,13 @@ func testQueryBindingBoolFail(t *testing.T, method, path, badPath, body, badBody
|
||||||
obj := FooStructForBoolType{}
|
obj := FooStructForBoolType{}
|
||||||
req := requestWithBody(method, path, body)
|
req := requestWithBody(method, path, body)
|
||||||
if method == "POST" {
|
if method == "POST" {
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
}
|
}
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
func testBodyBinding(t *testing.T, b common.Binding, name, path, badPath, body, badBody string) {
|
||||||
assert.Equal(t, name, b.Name())
|
assert.Equal(t, name, b.Name())
|
||||||
|
|
||||||
obj := FooStruct{}
|
obj := FooStruct{}
|
||||||
|
@ -1336,16 +1343,16 @@ func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody
|
||||||
|
|
||||||
obj = FooStruct{}
|
obj = FooStruct{}
|
||||||
req = requestWithBody("POST", badPath, badBody)
|
req = requestWithBody("POST", badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBodyBindingUseNumber(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
func testBodyBindingUseNumber(t *testing.T, b common.Binding, name, path, badPath, body, badBody string) {
|
||||||
assert.Equal(t, name, b.Name())
|
assert.Equal(t, name, b.Name())
|
||||||
|
|
||||||
obj := FooStructUseNumber{}
|
obj := FooStructUseNumber{}
|
||||||
req := requestWithBody("POST", path, body)
|
req := requestWithBody("POST", path, body)
|
||||||
EnableDecoderUseNumber = true
|
common.EnableDecoderUseNumber = true
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// we hope it is int64(123)
|
// we hope it is int64(123)
|
||||||
|
@ -1355,16 +1362,16 @@ func testBodyBindingUseNumber(t *testing.T, b Binding, name, path, badPath, body
|
||||||
|
|
||||||
obj = FooStructUseNumber{}
|
obj = FooStructUseNumber{}
|
||||||
req = requestWithBody("POST", badPath, badBody)
|
req = requestWithBody("POST", badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBodyBindingUseNumber2(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
func testBodyBindingUseNumber2(t *testing.T, b common.Binding, name, path, badPath, body, badBody string) {
|
||||||
assert.Equal(t, name, b.Name())
|
assert.Equal(t, name, b.Name())
|
||||||
|
|
||||||
obj := FooStructUseNumber{}
|
obj := FooStructUseNumber{}
|
||||||
req := requestWithBody("POST", path, body)
|
req := requestWithBody("POST", path, body)
|
||||||
EnableDecoderUseNumber = false
|
common.EnableDecoderUseNumber = false
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
// it will return float64(123) if not use EnableDecoderUseNumber
|
// it will return float64(123) if not use EnableDecoderUseNumber
|
||||||
|
@ -1373,11 +1380,11 @@ func testBodyBindingUseNumber2(t *testing.T, b Binding, name, path, badPath, bod
|
||||||
|
|
||||||
obj = FooStructUseNumber{}
|
obj = FooStructUseNumber{}
|
||||||
req = requestWithBody("POST", badPath, badBody)
|
req = requestWithBody("POST", badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
func testBodyBindingFail(t *testing.T, b common.Binding, name, path, badPath, body, badBody string) {
|
||||||
assert.Equal(t, name, b.Name())
|
assert.Equal(t, name, b.Name())
|
||||||
|
|
||||||
obj := FooStruct{}
|
obj := FooStruct{}
|
||||||
|
@ -1388,24 +1395,24 @@ func testBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, bad
|
||||||
|
|
||||||
obj = FooStruct{}
|
obj = FooStruct{}
|
||||||
req = requestWithBody("POST", badPath, badBody)
|
req = requestWithBody("POST", badPath, badBody)
|
||||||
err = JSON.Bind(req, &obj)
|
err = JSON().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
func testProtoBodyBinding(t *testing.T, b common.Binding, name, path, badPath, body, badBody string) {
|
||||||
assert.Equal(t, name, b.Name())
|
assert.Equal(t, name, b.Name())
|
||||||
|
|
||||||
obj := protoexample.Test{}
|
obj := protoexample.Test{}
|
||||||
req := requestWithBody("POST", path, body)
|
req := requestWithBody("POST", path, body)
|
||||||
req.Header.Add("Content-Type", MIMEPROTOBUF)
|
req.Header.Add("Content-Type", common.MIMEPROTOBUF)
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "yes", *obj.Label)
|
assert.Equal(t, "yes", *obj.Label)
|
||||||
|
|
||||||
obj = protoexample.Test{}
|
obj = protoexample.Test{}
|
||||||
req = requestWithBody("POST", badPath, badBody)
|
req = requestWithBody("POST", badPath, badBody)
|
||||||
req.Header.Add("Content-Type", MIMEPROTOBUF)
|
req.Header.Add("Content-Type", common.MIMEPROTOBUF)
|
||||||
err = ProtoBuf.Bind(req, &obj)
|
err = ProtoBuf().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1415,38 +1422,38 @@ func (h hook) Read([]byte) (int, error) {
|
||||||
return 0, errors.New("error")
|
return 0, errors.New("error")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
func testProtoBodyBindingFail(t *testing.T, b common.Binding, name, path, badPath, body, badBody string) {
|
||||||
assert.Equal(t, name, b.Name())
|
assert.Equal(t, name, b.Name())
|
||||||
|
|
||||||
obj := protoexample.Test{}
|
obj := protoexample.Test{}
|
||||||
req := requestWithBody("POST", path, body)
|
req := requestWithBody("POST", path, body)
|
||||||
|
|
||||||
req.Body = ioutil.NopCloser(&hook{})
|
req.Body = ioutil.NopCloser(&hook{})
|
||||||
req.Header.Add("Content-Type", MIMEPROTOBUF)
|
req.Header.Add("Content-Type", common.MIMEPROTOBUF)
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
obj = protoexample.Test{}
|
obj = protoexample.Test{}
|
||||||
req = requestWithBody("POST", badPath, badBody)
|
req = requestWithBody("POST", badPath, badBody)
|
||||||
req.Header.Add("Content-Type", MIMEPROTOBUF)
|
req.Header.Add("Content-Type", common.MIMEPROTOBUF)
|
||||||
err = ProtoBuf.Bind(req, &obj)
|
err = ProtoBuf().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMsgPackBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
|
func testMsgPackBodyBinding(t *testing.T, b common.Binding, name, path, badPath, body, badBody string) {
|
||||||
assert.Equal(t, name, b.Name())
|
assert.Equal(t, name, b.Name())
|
||||||
|
|
||||||
obj := FooStruct{}
|
obj := FooStruct{}
|
||||||
req := requestWithBody("POST", path, body)
|
req := requestWithBody("POST", path, body)
|
||||||
req.Header.Add("Content-Type", MIMEMSGPACK)
|
req.Header.Add("Content-Type", common.MIMEMSGPACK)
|
||||||
err := b.Bind(req, &obj)
|
err := b.Bind(req, &obj)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "bar", obj.Foo)
|
assert.Equal(t, "bar", obj.Foo)
|
||||||
|
|
||||||
obj = FooStruct{}
|
obj = FooStruct{}
|
||||||
req = requestWithBody("POST", badPath, badBody)
|
req = requestWithBody("POST", badPath, badBody)
|
||||||
req.Header.Add("Content-Type", MIMEMSGPACK)
|
req.Header.Add("Content-Type", common.MIMEMSGPACK)
|
||||||
err = MsgPack.Bind(req, &obj)
|
err = MsgPack().Bind(req, &obj)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1466,7 +1473,7 @@ func TestCanSet(t *testing.T) {
|
||||||
|
|
||||||
func formPostRequest(path, body string) *http.Request {
|
func formPostRequest(path, body string) *http.Request {
|
||||||
req := requestWithBody("POST", path, body)
|
req := requestWithBody("POST", path, body)
|
||||||
req.Header.Add("Content-Type", MIMEPOSTForm)
|
req.Header.Add("Content-Type", common.MIMEPOSTForm)
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1548,3 +1555,14 @@ func TestBindingArray(t *testing.T) {
|
||||||
err = Form.Bind(req, &s)
|
err = Form.Bind(req, &s)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBindingPanic(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Errorf("retBinding did not panic")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
//Should panic
|
||||||
|
retBinding("NotKnowBinding")
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// Content-Type MIME of the most common data formats.
|
||||||
|
const (
|
||||||
|
MIMEJSON = "application/json"
|
||||||
|
MIMEHTML = "text/html"
|
||||||
|
MIMEXML = "application/xml"
|
||||||
|
MIMEXML2 = "text/xml"
|
||||||
|
MIMEPlain = "text/plain"
|
||||||
|
MIMEPOSTForm = "application/x-www-form-urlencoded"
|
||||||
|
MIMEMultipartPOSTForm = "multipart/form-data"
|
||||||
|
MIMEPROTOBUF = "application/x-protobuf"
|
||||||
|
MIMEMSGPACK = "application/x-msgpack"
|
||||||
|
MIMEMSGPACK2 = "application/msgpack"
|
||||||
|
MIMEYAML = "application/x-yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
//List hold the defined binder
|
||||||
|
var List = map[string]BindingBody{}
|
||||||
|
|
||||||
|
// Binding describes the interface which needs to be implemented for binding the
|
||||||
|
// data present in the request such as JSON request body, query parameters or
|
||||||
|
// the form POST.
|
||||||
|
type Binding interface {
|
||||||
|
Name() string
|
||||||
|
Bind(*http.Request, interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindingBody adds BindBody method to Binding. BindBody is similar with Bind,
|
||||||
|
// but it reads the body from supplied bytes instead of req.Body.
|
||||||
|
type BindingBody interface {
|
||||||
|
Binding
|
||||||
|
BindBody([]byte, interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindingUri adds BindUri method to Binding. BindUri is similar with Bind,
|
||||||
|
// but it read the Params.
|
||||||
|
type BindingUri interface {
|
||||||
|
Name() string
|
||||||
|
BindUri(map[string][]string, interface{}) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableDecoderUseNumber is used to call the UseNumber method on the JSON
|
||||||
|
// Decoder instance. UseNumber causes the Decoder to unmarshal a number into an
|
||||||
|
// interface{} as a Number instead of as a float64.
|
||||||
|
var EnableDecoderUseNumber = false
|
||||||
|
|
||||||
|
// StructValidator is the minimal interface which needs to be implemented in
|
||||||
|
// order for it to be used as the validator engine for ensuring the correctness
|
||||||
|
// of the request. Gin provides a default implementation for this using
|
||||||
|
// https://github.com/go-playground/validator/tree/v8.18.2.
|
||||||
|
type StructValidator interface {
|
||||||
|
// ValidateStruct can receive any kind of type and it should never panic, even if the configuration is not right.
|
||||||
|
// If the received type is not a struct, any validation should be skipped and nil must be returned.
|
||||||
|
// If the received type is a struct or pointer to a struct, the validation should be performed.
|
||||||
|
// If the struct is not valid or the validation itself fails, a descriptive error should be returned.
|
||||||
|
// Otherwise nil must be returned.
|
||||||
|
ValidateStruct(interface{}) error
|
||||||
|
|
||||||
|
// Engine returns the underlying validator engine which powers the
|
||||||
|
// StructValidator implementation.
|
||||||
|
Engine() interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validator is the default validator which implements the StructValidator
|
||||||
|
// interface. It uses https://github.com/go-playground/validator/tree/v8.18.2
|
||||||
|
// under the hood.
|
||||||
|
var Validator StructValidator = &defaultValidator{}
|
||||||
|
|
||||||
|
//Validate standard validate object
|
||||||
|
func Validate(obj interface{}) error {
|
||||||
|
if Validator == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return Validator.ValidateStruct(obj)
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package binding
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package binding
|
package common
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -114,10 +114,10 @@ func TestValidateNoValidationValues(t *testing.T) {
|
||||||
test := createNoValidationValues()
|
test := createNoValidationValues()
|
||||||
empty := structNoValidationValues{}
|
empty := structNoValidationValues{}
|
||||||
|
|
||||||
assert.Nil(t, validate(test))
|
assert.Nil(t, Validate(test))
|
||||||
assert.Nil(t, validate(&test))
|
assert.Nil(t, Validate(&test))
|
||||||
assert.Nil(t, validate(empty))
|
assert.Nil(t, Validate(empty))
|
||||||
assert.Nil(t, validate(&empty))
|
assert.Nil(t, Validate(&empty))
|
||||||
|
|
||||||
assert.Equal(t, origin, test)
|
assert.Equal(t, origin, test)
|
||||||
}
|
}
|
||||||
|
@ -162,10 +162,10 @@ func TestValidateNoValidationPointers(t *testing.T) {
|
||||||
//test := createNoValidation_values()
|
//test := createNoValidation_values()
|
||||||
empty := structNoValidationPointer{}
|
empty := structNoValidationPointer{}
|
||||||
|
|
||||||
//assert.Nil(t, validate(test))
|
//assert.Nil(t, Validate(test))
|
||||||
//assert.Nil(t, validate(&test))
|
//assert.Nil(t, Validate(&test))
|
||||||
assert.Nil(t, validate(empty))
|
assert.Nil(t, Validate(empty))
|
||||||
assert.Nil(t, validate(&empty))
|
assert.Nil(t, Validate(&empty))
|
||||||
|
|
||||||
//assert.Equal(t, origin, test)
|
//assert.Equal(t, origin, test)
|
||||||
}
|
}
|
||||||
|
@ -174,22 +174,22 @@ type Object map[string]interface{}
|
||||||
|
|
||||||
func TestValidatePrimitives(t *testing.T) {
|
func TestValidatePrimitives(t *testing.T) {
|
||||||
obj := Object{"foo": "bar", "bar": 1}
|
obj := Object{"foo": "bar", "bar": 1}
|
||||||
assert.NoError(t, validate(obj))
|
assert.NoError(t, Validate(obj))
|
||||||
assert.NoError(t, validate(&obj))
|
assert.NoError(t, Validate(&obj))
|
||||||
assert.Equal(t, Object{"foo": "bar", "bar": 1}, obj)
|
assert.Equal(t, Object{"foo": "bar", "bar": 1}, obj)
|
||||||
|
|
||||||
obj2 := []Object{{"foo": "bar", "bar": 1}, {"foo": "bar", "bar": 1}}
|
obj2 := []Object{{"foo": "bar", "bar": 1}, {"foo": "bar", "bar": 1}}
|
||||||
assert.NoError(t, validate(obj2))
|
assert.NoError(t, Validate(obj2))
|
||||||
assert.NoError(t, validate(&obj2))
|
assert.NoError(t, Validate(&obj2))
|
||||||
|
|
||||||
nu := 10
|
nu := 10
|
||||||
assert.NoError(t, validate(nu))
|
assert.NoError(t, Validate(nu))
|
||||||
assert.NoError(t, validate(&nu))
|
assert.NoError(t, Validate(&nu))
|
||||||
assert.Equal(t, 10, nu)
|
assert.Equal(t, 10, nu)
|
||||||
|
|
||||||
str := "value"
|
str := "value"
|
||||||
assert.NoError(t, validate(str))
|
assert.NoError(t, Validate(str))
|
||||||
assert.NoError(t, validate(&str))
|
assert.NoError(t, Validate(&str))
|
||||||
assert.Equal(t, "value", str)
|
assert.Equal(t, "value", str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ func TestValidatorEngine(t *testing.T) {
|
||||||
|
|
||||||
// Create an instance which will fail validation
|
// Create an instance which will fail validation
|
||||||
withOne := structCustomValidation{Integer: 1}
|
withOne := structCustomValidation{Integer: 1}
|
||||||
errs := validate(withOne)
|
errs := Validate(withOne)
|
||||||
|
|
||||||
// Check that we got back non-nil errs
|
// Check that we got back non-nil errs
|
||||||
assert.NotNil(t, errs)
|
assert.NotNil(t, errs)
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
const defaultMemory = 32 * 1024 * 1024
|
const defaultMemory = 32 * 1024 * 1024
|
||||||
|
@ -32,7 +34,7 @@ func (formBinding) Bind(req *http.Request, obj interface{}) error {
|
||||||
if err := mapForm(obj, req.Form); err != nil {
|
if err := mapForm(obj, req.Form); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return validate(obj)
|
return common.Validate(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (formPostBinding) Name() string {
|
func (formPostBinding) Name() string {
|
||||||
|
@ -46,7 +48,7 @@ func (formPostBinding) Bind(req *http.Request, obj interface{}) error {
|
||||||
if err := mapForm(obj, req.PostForm); err != nil {
|
if err := mapForm(obj, req.PostForm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return validate(obj)
|
return common.Validate(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (formMultipartBinding) Name() string {
|
func (formMultipartBinding) Name() string {
|
||||||
|
@ -61,7 +63,7 @@ func (formMultipartBinding) Bind(req *http.Request, obj interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return validate(obj)
|
return common.Validate(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
type multipartRequest http.Request
|
type multipartRequest http.Request
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package binding
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -10,13 +10,13 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
"github.com/gin-gonic/gin/internal/json"
|
"github.com/gin-gonic/gin/internal/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnableDecoderUseNumber is used to call the UseNumber method on the JSON
|
func init() {
|
||||||
// Decoder instance. UseNumber causes the Decoder to unmarshal a number into an
|
common.List[common.MIMEJSON] = jsonBinding{}
|
||||||
// interface{} as a Number instead of as a float64.
|
}
|
||||||
var EnableDecoderUseNumber = false
|
|
||||||
|
|
||||||
type jsonBinding struct{}
|
type jsonBinding struct{}
|
||||||
|
|
||||||
|
@ -37,11 +37,11 @@ func (jsonBinding) BindBody(body []byte, obj interface{}) error {
|
||||||
|
|
||||||
func decodeJSON(r io.Reader, obj interface{}) error {
|
func decodeJSON(r io.Reader, obj interface{}) error {
|
||||||
decoder := json.NewDecoder(r)
|
decoder := json.NewDecoder(r)
|
||||||
if EnableDecoderUseNumber {
|
if common.EnableDecoderUseNumber {
|
||||||
decoder.UseNumber()
|
decoder.UseNumber()
|
||||||
}
|
}
|
||||||
if err := decoder.Decode(obj); err != nil {
|
if err := decoder.Decode(obj); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return validate(obj)
|
return common.Validate(obj)
|
||||||
}
|
}
|
|
@ -2,16 +2,23 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package binding
|
package msgpack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
"github.com/ugorji/go/codec"
|
"github.com/ugorji/go/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
msgPack := msgpackBinding{}
|
||||||
|
common.List[common.MIMEMSGPACK] = msgPack
|
||||||
|
common.List[common.MIMEMSGPACK2] = msgPack
|
||||||
|
}
|
||||||
|
|
||||||
type msgpackBinding struct{}
|
type msgpackBinding struct{}
|
||||||
|
|
||||||
func (msgpackBinding) Name() string {
|
func (msgpackBinding) Name() string {
|
||||||
|
@ -31,5 +38,5 @@ func decodeMsgPack(r io.Reader, obj interface{}) error {
|
||||||
if err := codec.NewDecoder(r, cdc).Decode(&obj); err != nil {
|
if err := codec.NewDecoder(r, cdc).Decode(&obj); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return validate(obj)
|
return common.Validate(obj)
|
||||||
}
|
}
|
|
@ -2,15 +2,20 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package binding
|
package protobuf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.List[common.MIMEPROTOBUF] = protobufBinding{}
|
||||||
|
}
|
||||||
|
|
||||||
type protobufBinding struct{}
|
type protobufBinding struct{}
|
||||||
|
|
||||||
func (protobufBinding) Name() string {
|
func (protobufBinding) Name() string {
|
|
@ -4,7 +4,11 @@
|
||||||
|
|
||||||
package binding
|
package binding
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
|
)
|
||||||
|
|
||||||
type queryBinding struct{}
|
type queryBinding struct{}
|
||||||
|
|
||||||
|
@ -17,5 +21,5 @@ func (queryBinding) Bind(req *http.Request, obj interface{}) error {
|
||||||
if err := mapForm(obj, values); err != nil {
|
if err := mapForm(obj, values); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return validate(obj)
|
return common.Validate(obj)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package binding
|
package binding
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin/binding/common"
|
||||||
|
|
||||||
type uriBinding struct{}
|
type uriBinding struct{}
|
||||||
|
|
||||||
func (uriBinding) Name() string {
|
func (uriBinding) Name() string {
|
||||||
|
@ -14,5 +16,5 @@ func (uriBinding) BindUri(m map[string][]string, obj interface{}) error {
|
||||||
if err := mapUri(obj, m); err != nil {
|
if err := mapUri(obj, m); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return validate(obj)
|
return common.Validate(obj)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,23 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package binding
|
package xml
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
xml := xmlBinding{}
|
||||||
|
common.List[common.MIMEXML] = xml
|
||||||
|
common.List[common.MIMEXML2] = xml
|
||||||
|
}
|
||||||
|
|
||||||
type xmlBinding struct{}
|
type xmlBinding struct{}
|
||||||
|
|
||||||
func (xmlBinding) Name() string {
|
func (xmlBinding) Name() string {
|
||||||
|
@ -29,5 +37,5 @@ func decodeXML(r io.Reader, obj interface{}) error {
|
||||||
if err := decoder.Decode(obj); err != nil {
|
if err := decoder.Decode(obj); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return validate(obj)
|
return common.Validate(obj)
|
||||||
}
|
}
|
|
@ -2,16 +2,21 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package binding
|
package yaml
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.List[common.MIMEYAML] = yamlBinding{}
|
||||||
|
}
|
||||||
|
|
||||||
type yamlBinding struct{}
|
type yamlBinding struct{}
|
||||||
|
|
||||||
func (yamlBinding) Name() string {
|
func (yamlBinding) Name() string {
|
||||||
|
@ -31,5 +36,5 @@ func decodeYAML(r io.Reader, obj interface{}) error {
|
||||||
if err := decoder.Decode(obj); err != nil {
|
if err := decoder.Decode(obj); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return validate(obj)
|
return common.Validate(obj)
|
||||||
}
|
}
|
63
context.go
63
context.go
|
@ -18,22 +18,16 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
commonB "github.com/gin-gonic/gin/binding/common"
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
|
|
||||||
"github.com/gin-contrib/sse"
|
"github.com/gin-contrib/sse"
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
"github.com/gin-gonic/gin/render"
|
"github.com/gin-gonic/gin/render"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Content-Type MIME of the most common data formats.
|
|
||||||
const (
|
const (
|
||||||
MIMEJSON = binding.MIMEJSON
|
BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
|
||||||
MIMEHTML = binding.MIMEHTML
|
|
||||||
MIMEXML = binding.MIMEXML
|
|
||||||
MIMEXML2 = binding.MIMEXML2
|
|
||||||
MIMEPlain = binding.MIMEPlain
|
|
||||||
MIMEPOSTForm = binding.MIMEPOSTForm
|
|
||||||
MIMEMultipartPOSTForm = binding.MIMEMultipartPOSTForm
|
|
||||||
MIMEYAML = binding.MIMEYAML
|
|
||||||
BodyBytesKey = "_gin-gonic/gin/bodybyteskey"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const abortIndex int8 = math.MaxInt8 / 2
|
const abortIndex int8 = math.MaxInt8 / 2
|
||||||
|
@ -536,12 +530,12 @@ func (c *Context) Bind(obj interface{}) error {
|
||||||
|
|
||||||
// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
|
// BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
|
||||||
func (c *Context) BindJSON(obj interface{}) error {
|
func (c *Context) BindJSON(obj interface{}) error {
|
||||||
return c.MustBindWith(obj, binding.JSON)
|
return c.MustBindWith(obj, binding.JSON())
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML).
|
// BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML).
|
||||||
func (c *Context) BindXML(obj interface{}) error {
|
func (c *Context) BindXML(obj interface{}) error {
|
||||||
return c.MustBindWith(obj, binding.XML)
|
return c.MustBindWith(obj, binding.XML())
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindQuery is a shortcut for c.MustBindWith(obj, binding.Query).
|
// BindQuery is a shortcut for c.MustBindWith(obj, binding.Query).
|
||||||
|
@ -551,7 +545,7 @@ func (c *Context) BindQuery(obj interface{}) error {
|
||||||
|
|
||||||
// BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML).
|
// BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML).
|
||||||
func (c *Context) BindYAML(obj interface{}) error {
|
func (c *Context) BindYAML(obj interface{}) error {
|
||||||
return c.MustBindWith(obj, binding.YAML)
|
return c.MustBindWith(obj, binding.YAML())
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindUri binds the passed struct pointer using binding.Uri.
|
// BindUri binds the passed struct pointer using binding.Uri.
|
||||||
|
@ -567,7 +561,7 @@ func (c *Context) BindUri(obj interface{}) error {
|
||||||
// MustBindWith binds the passed struct pointer using the specified binding engine.
|
// MustBindWith binds the passed struct pointer using the specified binding engine.
|
||||||
// It will abort the request with HTTP 400 if any error occurs.
|
// It will abort the request with HTTP 400 if any error occurs.
|
||||||
// See the binding package.
|
// See the binding package.
|
||||||
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
|
func (c *Context) MustBindWith(obj interface{}, b commonB.Binding) error {
|
||||||
if err := c.ShouldBindWith(obj, b); err != nil {
|
if err := c.ShouldBindWith(obj, b); err != nil {
|
||||||
c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
|
c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
|
||||||
return err
|
return err
|
||||||
|
@ -590,12 +584,12 @@ func (c *Context) ShouldBind(obj interface{}) error {
|
||||||
|
|
||||||
// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
|
// ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
|
||||||
func (c *Context) ShouldBindJSON(obj interface{}) error {
|
func (c *Context) ShouldBindJSON(obj interface{}) error {
|
||||||
return c.ShouldBindWith(obj, binding.JSON)
|
return c.ShouldBindWith(obj, binding.JSON())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML).
|
// ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML).
|
||||||
func (c *Context) ShouldBindXML(obj interface{}) error {
|
func (c *Context) ShouldBindXML(obj interface{}) error {
|
||||||
return c.ShouldBindWith(obj, binding.XML)
|
return c.ShouldBindWith(obj, binding.XML())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query).
|
// ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query).
|
||||||
|
@ -605,7 +599,7 @@ func (c *Context) ShouldBindQuery(obj interface{}) error {
|
||||||
|
|
||||||
// ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML).
|
// ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML).
|
||||||
func (c *Context) ShouldBindYAML(obj interface{}) error {
|
func (c *Context) ShouldBindYAML(obj interface{}) error {
|
||||||
return c.ShouldBindWith(obj, binding.YAML)
|
return c.ShouldBindWith(obj, binding.YAML())
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShouldBindUri binds the passed struct pointer using the specified binding engine.
|
// ShouldBindUri binds the passed struct pointer using the specified binding engine.
|
||||||
|
@ -619,7 +613,7 @@ func (c *Context) ShouldBindUri(obj interface{}) error {
|
||||||
|
|
||||||
// ShouldBindWith binds the passed struct pointer using the specified binding engine.
|
// ShouldBindWith binds the passed struct pointer using the specified binding engine.
|
||||||
// See the binding package.
|
// See the binding package.
|
||||||
func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
|
func (c *Context) ShouldBindWith(obj interface{}, b commonB.Binding) error {
|
||||||
return b.Bind(c.Request, obj)
|
return b.Bind(c.Request, obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -628,7 +622,7 @@ func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
|
||||||
//
|
//
|
||||||
// NOTE: This method reads the body before binding. So you should use
|
// NOTE: This method reads the body before binding. So you should use
|
||||||
// ShouldBindWith for better performance if you need to call only once.
|
// ShouldBindWith for better performance if you need to call only once.
|
||||||
func (c *Context) ShouldBindBodyWith(obj interface{}, bb binding.BindingBody) (err error) {
|
func (c *Context) ShouldBindBodyWith(obj interface{}, bb commonB.BindingBody) (err error) {
|
||||||
var body []byte
|
var body []byte
|
||||||
if cb, ok := c.Get(BodyBytesKey); ok {
|
if cb, ok := c.Get(BodyBytesKey); ok {
|
||||||
if cbb, ok := cb.([]byte); ok {
|
if cbb, ok := cb.([]byte); ok {
|
||||||
|
@ -767,7 +761,7 @@ func (c *Context) Cookie(name string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render writes the response headers and calls render.Render to render data.
|
// Render writes the response headers and calls render.Render to render data.
|
||||||
func (c *Context) Render(code int, r render.Render) {
|
func (c *Context) Render(code int, r common.Render) {
|
||||||
c.Status(code)
|
c.Status(code)
|
||||||
|
|
||||||
if !bodyAllowedForStatus(code) {
|
if !bodyAllowedForStatus(code) {
|
||||||
|
@ -794,14 +788,14 @@ func (c *Context) HTML(code int, name string, obj interface{}) {
|
||||||
// WARNING: we recommend to use this only for development purposes since printing pretty JSON is
|
// WARNING: we recommend to use this only for development purposes since printing pretty JSON is
|
||||||
// more CPU and bandwidth consuming. Use Context.JSON() instead.
|
// more CPU and bandwidth consuming. Use Context.JSON() instead.
|
||||||
func (c *Context) IndentedJSON(code int, obj interface{}) {
|
func (c *Context) IndentedJSON(code int, obj interface{}) {
|
||||||
c.Render(code, render.IndentedJSON{Data: obj})
|
c.Render(code, render.IndentedJSON(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecureJSON serializes the given struct as Secure JSON into the response body.
|
// SecureJSON serializes the given struct as Secure JSON into the response body.
|
||||||
// Default prepends "while(1)," to response body if the given struct is array values.
|
// Default prepends "while(1)," to response body if the given struct is array values.
|
||||||
// It also sets the Content-Type as "application/json".
|
// It also sets the Content-Type as "application/json".
|
||||||
func (c *Context) SecureJSON(code int, obj interface{}) {
|
func (c *Context) SecureJSON(code int, obj interface{}) {
|
||||||
c.Render(code, render.SecureJSON{Prefix: c.engine.secureJsonPrefix, Data: obj})
|
c.Render(code, render.SecureJSON(c.engine.secureJsonPrefix, obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONP serializes the given struct as JSON into the response body.
|
// JSONP serializes the given struct as JSON into the response body.
|
||||||
|
@ -810,38 +804,43 @@ func (c *Context) SecureJSON(code int, obj interface{}) {
|
||||||
func (c *Context) JSONP(code int, obj interface{}) {
|
func (c *Context) JSONP(code int, obj interface{}) {
|
||||||
callback := c.DefaultQuery("callback", "")
|
callback := c.DefaultQuery("callback", "")
|
||||||
if callback == "" {
|
if callback == "" {
|
||||||
c.Render(code, render.JSON{Data: obj})
|
c.Render(code, render.JSON(obj))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.Render(code, render.JsonpJSON{Callback: callback, Data: obj})
|
c.Render(code, render.JsonpJSON(callback, obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSON serializes the given struct as JSON into the response body.
|
// JSON serializes the given struct as JSON into the response body.
|
||||||
// It also sets the Content-Type as "application/json".
|
// It also sets the Content-Type as "application/json".
|
||||||
func (c *Context) JSON(code int, obj interface{}) {
|
func (c *Context) JSON(code int, obj interface{}) {
|
||||||
c.Render(code, render.JSON{Data: obj})
|
c.Render(code, render.JSON(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string.
|
// AsciiJSON serializes the given struct as JSON into the response body with unicode to ASCII string.
|
||||||
// It also sets the Content-Type as "application/json".
|
// It also sets the Content-Type as "application/json".
|
||||||
func (c *Context) AsciiJSON(code int, obj interface{}) {
|
func (c *Context) AsciiJSON(code int, obj interface{}) {
|
||||||
c.Render(code, render.AsciiJSON{Data: obj})
|
c.Render(code, render.AsciiJSON(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
// XML serializes the given struct as XML into the response body.
|
// XML serializes the given struct as XML into the response body.
|
||||||
// It also sets the Content-Type as "application/xml".
|
// It also sets the Content-Type as "application/xml".
|
||||||
func (c *Context) XML(code int, obj interface{}) {
|
func (c *Context) XML(code int, obj interface{}) {
|
||||||
c.Render(code, render.XML{Data: obj})
|
c.Render(code, render.XML(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
// YAML serializes the given struct as YAML into the response body.
|
// YAML serializes the given struct as YAML into the response body.
|
||||||
func (c *Context) YAML(code int, obj interface{}) {
|
func (c *Context) YAML(code int, obj interface{}) {
|
||||||
c.Render(code, render.YAML{Data: obj})
|
c.Render(code, render.YAML(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProtoBuf serializes the given struct as ProtoBuf into the response body.
|
// ProtoBuf serializes the given struct as ProtoBuf into the response body.
|
||||||
func (c *Context) ProtoBuf(code int, obj interface{}) {
|
func (c *Context) ProtoBuf(code int, obj interface{}) {
|
||||||
c.Render(code, render.ProtoBuf{Data: obj})
|
c.Render(code, render.ProtoBuf(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MsgPack serializes the given struct as MsgPack into the response body.
|
||||||
|
func (c *Context) MsgPack(code int, obj interface{}) {
|
||||||
|
c.Render(code, render.MsgPack(obj))
|
||||||
}
|
}
|
||||||
|
|
||||||
// String writes the given string into the response body.
|
// String writes the given string into the response body.
|
||||||
|
@ -932,15 +931,15 @@ type Negotiate struct {
|
||||||
// Negotiate calls different Render according acceptable Accept format.
|
// Negotiate calls different Render according acceptable Accept format.
|
||||||
func (c *Context) Negotiate(code int, config Negotiate) {
|
func (c *Context) Negotiate(code int, config Negotiate) {
|
||||||
switch c.NegotiateFormat(config.Offered...) {
|
switch c.NegotiateFormat(config.Offered...) {
|
||||||
case binding.MIMEJSON:
|
case commonB.MIMEJSON:
|
||||||
data := chooseData(config.JSONData, config.Data)
|
data := chooseData(config.JSONData, config.Data)
|
||||||
c.JSON(code, data)
|
c.JSON(code, data)
|
||||||
|
|
||||||
case binding.MIMEHTML:
|
case commonB.MIMEHTML:
|
||||||
data := chooseData(config.HTMLData, config.Data)
|
data := chooseData(config.HTMLData, config.Data)
|
||||||
c.HTML(code, config.HTMLName, data)
|
c.HTML(code, config.HTMLName, data)
|
||||||
|
|
||||||
case binding.MIMEXML:
|
case commonB.MIMEXML:
|
||||||
data := chooseData(config.XMLData, config.Data)
|
data := chooseData(config.XMLData, config.Data)
|
||||||
c.XML(code, data)
|
c.XML(code, data)
|
||||||
|
|
||||||
|
|
|
@ -13,5 +13,5 @@ import (
|
||||||
// PureJSON serializes the given struct as JSON into the response body.
|
// PureJSON serializes the given struct as JSON into the response body.
|
||||||
// PureJSON, unlike JSON, does not replace special html characters with their unicode entities.
|
// PureJSON, unlike JSON, does not replace special html characters with their unicode entities.
|
||||||
func (c *Context) PureJSON(code int, obj interface{}) {
|
func (c *Context) PureJSON(code int, obj interface{}) {
|
||||||
c.Render(code, render.PureJSON{Data: obj})
|
c.Render(code, render.PureJSON(obj))
|
||||||
}
|
}
|
||||||
|
|
116
context_test.go
116
context_test.go
|
@ -20,11 +20,23 @@ import (
|
||||||
|
|
||||||
"github.com/gin-contrib/sse"
|
"github.com/gin-contrib/sse"
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
commonB "github.com/gin-gonic/gin/binding/common"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/ugorji/go/codec"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
testdata "github.com/gin-gonic/gin/testdata/protoexample"
|
testdata "github.com/gin-gonic/gin/testdata/protoexample"
|
||||||
|
|
||||||
|
_ "github.com/gin-gonic/gin/binding/json"
|
||||||
|
_ "github.com/gin-gonic/gin/binding/xml"
|
||||||
|
_ "github.com/gin-gonic/gin/binding/yaml"
|
||||||
|
|
||||||
|
_ "github.com/gin-gonic/gin/render/json"
|
||||||
|
_ "github.com/gin-gonic/gin/render/msgpack"
|
||||||
|
_ "github.com/gin-gonic/gin/render/protobuf"
|
||||||
|
_ "github.com/gin-gonic/gin/render/xml"
|
||||||
|
_ "github.com/gin-gonic/gin/render/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ context.Context = &Context{}
|
var _ context.Context = &Context{}
|
||||||
|
@ -55,7 +67,7 @@ func createMultipartRequest() *http.Request {
|
||||||
must(mw.WriteField("names[b]", "tianou"))
|
must(mw.WriteField("names[b]", "tianou"))
|
||||||
req, err := http.NewRequest("POST", "/", body)
|
req, err := http.NewRequest("POST", "/", body)
|
||||||
must(err)
|
must(err)
|
||||||
req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
|
req.Header.Set("Content-Type", commonB.MIMEMultipartPOSTForm+"; boundary="+boundary)
|
||||||
return req
|
return req
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,7 +425,7 @@ func TestContextQueryAndPostForm(t *testing.T) {
|
||||||
body := bytes.NewBufferString("foo=bar&page=11&both=&foo=second")
|
body := bytes.NewBufferString("foo=bar&page=11&both=&foo=second")
|
||||||
c.Request, _ = http.NewRequest("POST",
|
c.Request, _ = http.NewRequest("POST",
|
||||||
"/?both=GET&id=main&id=omit&array[]=first&array[]=second&ids[a]=hi&ids[b]=3.14", body)
|
"/?both=GET&id=main&id=omit&array[]=first&array[]=second&ids[a]=hi&ids[b]=3.14", body)
|
||||||
c.Request.Header.Add("Content-Type", MIMEPOSTForm)
|
c.Request.Header.Add("Content-Type", commonB.MIMEPOSTForm)
|
||||||
|
|
||||||
assert.Equal(t, "bar", c.DefaultPostForm("foo", "none"))
|
assert.Equal(t, "bar", c.DefaultPostForm("foo", "none"))
|
||||||
assert.Equal(t, "bar", c.PostForm("foo"))
|
assert.Equal(t, "bar", c.PostForm("foo"))
|
||||||
|
@ -1005,6 +1017,32 @@ func TestContextRenderYAML(t *testing.T) {
|
||||||
assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestContextRenderMsgPack tests that the response is serialized as MsgPack
|
||||||
|
// and Content-Type is set to application/msgpack; charset=utf-8
|
||||||
|
// and we just use the example MsgPack to check if the response is correct
|
||||||
|
func TestContextRenderMsgPack(t *testing.T) {
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
c, _ := CreateTestContext(w)
|
||||||
|
|
||||||
|
reps := []int64{int64(1), int64(2)}
|
||||||
|
label := "test"
|
||||||
|
data := &testdata.Test{
|
||||||
|
Label: &label,
|
||||||
|
Reps: reps,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.MsgPack(http.StatusCreated, data)
|
||||||
|
|
||||||
|
var mh codec.MsgpackHandle
|
||||||
|
var msgData bytes.Buffer
|
||||||
|
err := codec.NewEncoder(&msgData, &mh).Encode(data)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusCreated, w.Code)
|
||||||
|
assert.Equal(t, msgData.String(), w.Body.String())
|
||||||
|
assert.Equal(t, "application/msgpack; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
}
|
||||||
|
|
||||||
// TestContextRenderProtoBuf tests that the response is serialized as ProtoBuf
|
// TestContextRenderProtoBuf tests that the response is serialized as ProtoBuf
|
||||||
// and Content-Type is set to application/x-protobuf
|
// and Content-Type is set to application/x-protobuf
|
||||||
// and we just use the example protobuf to check if the response is correct
|
// and we just use the example protobuf to check if the response is correct
|
||||||
|
@ -1103,7 +1141,7 @@ func TestContextNegotiationWithJSON(t *testing.T) {
|
||||||
c.Request, _ = http.NewRequest("POST", "", nil)
|
c.Request, _ = http.NewRequest("POST", "", nil)
|
||||||
|
|
||||||
c.Negotiate(http.StatusOK, Negotiate{
|
c.Negotiate(http.StatusOK, Negotiate{
|
||||||
Offered: []string{MIMEJSON, MIMEXML},
|
Offered: []string{commonB.MIMEJSON, commonB.MIMEXML},
|
||||||
Data: H{"foo": "bar"},
|
Data: H{"foo": "bar"},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1118,7 +1156,7 @@ func TestContextNegotiationWithXML(t *testing.T) {
|
||||||
c.Request, _ = http.NewRequest("POST", "", nil)
|
c.Request, _ = http.NewRequest("POST", "", nil)
|
||||||
|
|
||||||
c.Negotiate(http.StatusOK, Negotiate{
|
c.Negotiate(http.StatusOK, Negotiate{
|
||||||
Offered: []string{MIMEXML, MIMEJSON},
|
Offered: []string{commonB.MIMEXML, commonB.MIMEJSON},
|
||||||
Data: H{"foo": "bar"},
|
Data: H{"foo": "bar"},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1135,7 +1173,7 @@ func TestContextNegotiationWithHTML(t *testing.T) {
|
||||||
router.SetHTMLTemplate(templ)
|
router.SetHTMLTemplate(templ)
|
||||||
|
|
||||||
c.Negotiate(http.StatusOK, Negotiate{
|
c.Negotiate(http.StatusOK, Negotiate{
|
||||||
Offered: []string{MIMEHTML},
|
Offered: []string{commonB.MIMEHTML},
|
||||||
Data: H{"name": "gin"},
|
Data: H{"name": "gin"},
|
||||||
HTMLName: "t",
|
HTMLName: "t",
|
||||||
})
|
})
|
||||||
|
@ -1151,7 +1189,7 @@ func TestContextNegotiationNotSupport(t *testing.T) {
|
||||||
c.Request, _ = http.NewRequest("POST", "", nil)
|
c.Request, _ = http.NewRequest("POST", "", nil)
|
||||||
|
|
||||||
c.Negotiate(http.StatusOK, Negotiate{
|
c.Negotiate(http.StatusOK, Negotiate{
|
||||||
Offered: []string{MIMEPOSTForm},
|
Offered: []string{commonB.MIMEPOSTForm},
|
||||||
})
|
})
|
||||||
|
|
||||||
assert.Equal(t, http.StatusNotAcceptable, w.Code)
|
assert.Equal(t, http.StatusNotAcceptable, w.Code)
|
||||||
|
@ -1164,8 +1202,8 @@ func TestContextNegotiationFormat(t *testing.T) {
|
||||||
c.Request, _ = http.NewRequest("POST", "", nil)
|
c.Request, _ = http.NewRequest("POST", "", nil)
|
||||||
|
|
||||||
assert.Panics(t, func() { c.NegotiateFormat() })
|
assert.Panics(t, func() { c.NegotiateFormat() })
|
||||||
assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML))
|
assert.Equal(t, commonB.MIMEJSON, c.NegotiateFormat(commonB.MIMEJSON, commonB.MIMEXML))
|
||||||
assert.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEHTML, MIMEJSON))
|
assert.Equal(t, commonB.MIMEHTML, c.NegotiateFormat(commonB.MIMEHTML, commonB.MIMEJSON))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContextNegotiationFormatWithAccept(t *testing.T) {
|
func TestContextNegotiationFormatWithAccept(t *testing.T) {
|
||||||
|
@ -1173,9 +1211,9 @@ func TestContextNegotiationFormatWithAccept(t *testing.T) {
|
||||||
c.Request, _ = http.NewRequest("POST", "/", nil)
|
c.Request, _ = http.NewRequest("POST", "/", nil)
|
||||||
c.Request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8")
|
c.Request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8")
|
||||||
|
|
||||||
assert.Equal(t, MIMEXML, c.NegotiateFormat(MIMEJSON, MIMEXML))
|
assert.Equal(t, commonB.MIMEXML, c.NegotiateFormat(commonB.MIMEJSON, commonB.MIMEXML))
|
||||||
assert.Equal(t, MIMEHTML, c.NegotiateFormat(MIMEXML, MIMEHTML))
|
assert.Equal(t, commonB.MIMEHTML, c.NegotiateFormat(commonB.MIMEXML, commonB.MIMEHTML))
|
||||||
assert.Empty(t, c.NegotiateFormat(MIMEJSON))
|
assert.Empty(t, c.NegotiateFormat(commonB.MIMEJSON))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContextNegotiationFormatWithWildcardAccept(t *testing.T) {
|
func TestContextNegotiationFormatWithWildcardAccept(t *testing.T) {
|
||||||
|
@ -1186,9 +1224,9 @@ func TestContextNegotiationFormatWithWildcardAccept(t *testing.T) {
|
||||||
assert.Equal(t, c.NegotiateFormat("*/*"), "*/*")
|
assert.Equal(t, c.NegotiateFormat("*/*"), "*/*")
|
||||||
assert.Equal(t, c.NegotiateFormat("text/*"), "text/*")
|
assert.Equal(t, c.NegotiateFormat("text/*"), "text/*")
|
||||||
assert.Equal(t, c.NegotiateFormat("application/*"), "application/*")
|
assert.Equal(t, c.NegotiateFormat("application/*"), "application/*")
|
||||||
assert.Equal(t, c.NegotiateFormat(MIMEJSON), MIMEJSON)
|
assert.Equal(t, c.NegotiateFormat(commonB.MIMEJSON), commonB.MIMEJSON)
|
||||||
assert.Equal(t, c.NegotiateFormat(MIMEXML), MIMEXML)
|
assert.Equal(t, c.NegotiateFormat(commonB.MIMEXML), commonB.MIMEXML)
|
||||||
assert.Equal(t, c.NegotiateFormat(MIMEHTML), MIMEHTML)
|
assert.Equal(t, c.NegotiateFormat(commonB.MIMEHTML), commonB.MIMEHTML)
|
||||||
|
|
||||||
c, _ = CreateTestContext(httptest.NewRecorder())
|
c, _ = CreateTestContext(httptest.NewRecorder())
|
||||||
c.Request, _ = http.NewRequest("POST", "/", nil)
|
c.Request, _ = http.NewRequest("POST", "/", nil)
|
||||||
|
@ -1197,9 +1235,9 @@ func TestContextNegotiationFormatWithWildcardAccept(t *testing.T) {
|
||||||
assert.Equal(t, c.NegotiateFormat("*/*"), "*/*")
|
assert.Equal(t, c.NegotiateFormat("*/*"), "*/*")
|
||||||
assert.Equal(t, c.NegotiateFormat("text/*"), "text/*")
|
assert.Equal(t, c.NegotiateFormat("text/*"), "text/*")
|
||||||
assert.Equal(t, c.NegotiateFormat("application/*"), "")
|
assert.Equal(t, c.NegotiateFormat("application/*"), "")
|
||||||
assert.Equal(t, c.NegotiateFormat(MIMEJSON), "")
|
assert.Equal(t, c.NegotiateFormat(commonB.MIMEJSON), "")
|
||||||
assert.Equal(t, c.NegotiateFormat(MIMEXML), "")
|
assert.Equal(t, c.NegotiateFormat(commonB.MIMEXML), "")
|
||||||
assert.Equal(t, c.NegotiateFormat(MIMEHTML), MIMEHTML)
|
assert.Equal(t, c.NegotiateFormat(commonB.MIMEHTML), commonB.MIMEHTML)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContextNegotiationFormatCustom(t *testing.T) {
|
func TestContextNegotiationFormatCustom(t *testing.T) {
|
||||||
|
@ -1208,11 +1246,11 @@ func TestContextNegotiationFormatCustom(t *testing.T) {
|
||||||
c.Request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8")
|
c.Request.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9;q=0.8")
|
||||||
|
|
||||||
c.Accepted = nil
|
c.Accepted = nil
|
||||||
c.SetAccepted(MIMEJSON, MIMEXML)
|
c.SetAccepted(commonB.MIMEJSON, commonB.MIMEXML)
|
||||||
|
|
||||||
assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON, MIMEXML))
|
assert.Equal(t, commonB.MIMEJSON, c.NegotiateFormat(commonB.MIMEJSON, commonB.MIMEXML))
|
||||||
assert.Equal(t, MIMEXML, c.NegotiateFormat(MIMEXML, MIMEHTML))
|
assert.Equal(t, commonB.MIMEXML, c.NegotiateFormat(commonB.MIMEXML, commonB.MIMEHTML))
|
||||||
assert.Equal(t, MIMEJSON, c.NegotiateFormat(MIMEJSON))
|
assert.Equal(t, commonB.MIMEJSON, c.NegotiateFormat(commonB.MIMEJSON))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContextIsAborted(t *testing.T) {
|
func TestContextIsAborted(t *testing.T) {
|
||||||
|
@ -1376,7 +1414,7 @@ func TestContextContentType(t *testing.T) {
|
||||||
func TestContextAutoBindJSON(t *testing.T) {
|
func TestContextAutoBindJSON(t *testing.T) {
|
||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||||
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
||||||
c.Request.Header.Add("Content-Type", MIMEJSON)
|
c.Request.Header.Add("Content-Type", commonB.MIMEJSON)
|
||||||
|
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `json:"foo"`
|
Foo string `json:"foo"`
|
||||||
|
@ -1393,7 +1431,7 @@ func TestContextBindWithJSON(t *testing.T) {
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
|
|
||||||
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
||||||
c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type
|
c.Request.Header.Add("Content-Type", commonB.MIMEXML) // set fake content-type
|
||||||
|
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `json:"foo"`
|
Foo string `json:"foo"`
|
||||||
|
@ -1413,7 +1451,7 @@ func TestContextBindWithXML(t *testing.T) {
|
||||||
<foo>FOO</foo>
|
<foo>FOO</foo>
|
||||||
<bar>BAR</bar>
|
<bar>BAR</bar>
|
||||||
</root>`))
|
</root>`))
|
||||||
c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type
|
c.Request.Header.Add("Content-Type", commonB.MIMEXML) // set fake content-type
|
||||||
|
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `xml:"foo"`
|
Foo string `xml:"foo"`
|
||||||
|
@ -1446,7 +1484,7 @@ func TestContextBindWithYAML(t *testing.T) {
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
|
|
||||||
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo: bar\nbar: foo"))
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo: bar\nbar: foo"))
|
||||||
c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type
|
c.Request.Header.Add("Content-Type", commonB.MIMEXML) // set fake content-type
|
||||||
|
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `yaml:"foo"`
|
Foo string `yaml:"foo"`
|
||||||
|
@ -1463,7 +1501,7 @@ func TestContextBadAutoBind(t *testing.T) {
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
|
|
||||||
c.Request, _ = http.NewRequest("POST", "http://example.com", bytes.NewBufferString("\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
c.Request, _ = http.NewRequest("POST", "http://example.com", bytes.NewBufferString("\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
||||||
c.Request.Header.Add("Content-Type", MIMEJSON)
|
c.Request.Header.Add("Content-Type", commonB.MIMEJSON)
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `json:"foo"`
|
Foo string `json:"foo"`
|
||||||
Bar string `json:"bar"`
|
Bar string `json:"bar"`
|
||||||
|
@ -1482,7 +1520,7 @@ func TestContextBadAutoBind(t *testing.T) {
|
||||||
func TestContextAutoShouldBindJSON(t *testing.T) {
|
func TestContextAutoShouldBindJSON(t *testing.T) {
|
||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||||
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
||||||
c.Request.Header.Add("Content-Type", MIMEJSON)
|
c.Request.Header.Add("Content-Type", commonB.MIMEJSON)
|
||||||
|
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `json:"foo"`
|
Foo string `json:"foo"`
|
||||||
|
@ -1499,7 +1537,7 @@ func TestContextShouldBindWithJSON(t *testing.T) {
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
|
|
||||||
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
||||||
c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type
|
c.Request.Header.Add("Content-Type", commonB.MIMEXML) // set fake content-type
|
||||||
|
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `json:"foo"`
|
Foo string `json:"foo"`
|
||||||
|
@ -1520,7 +1558,7 @@ func TestContextShouldBindWithXML(t *testing.T) {
|
||||||
<foo>FOO</foo>
|
<foo>FOO</foo>
|
||||||
<bar>BAR</bar>
|
<bar>BAR</bar>
|
||||||
</root>`))
|
</root>`))
|
||||||
c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type
|
c.Request.Header.Add("Content-Type", commonB.MIMEXML) // set fake content-type
|
||||||
|
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `xml:"foo"`
|
Foo string `xml:"foo"`
|
||||||
|
@ -1557,7 +1595,7 @@ func TestContextShouldBindWithYAML(t *testing.T) {
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
|
|
||||||
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo: bar\nbar: foo"))
|
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("foo: bar\nbar: foo"))
|
||||||
c.Request.Header.Add("Content-Type", MIMEXML) // set fake content-type
|
c.Request.Header.Add("Content-Type", commonB.MIMEXML) // set fake content-type
|
||||||
|
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `yaml:"foo"`
|
Foo string `yaml:"foo"`
|
||||||
|
@ -1574,7 +1612,7 @@ func TestContextBadAutoShouldBind(t *testing.T) {
|
||||||
c, _ := CreateTestContext(w)
|
c, _ := CreateTestContext(w)
|
||||||
|
|
||||||
c.Request, _ = http.NewRequest("POST", "http://example.com", bytes.NewBufferString("\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
c.Request, _ = http.NewRequest("POST", "http://example.com", bytes.NewBufferString("\"foo\":\"bar\", \"bar\":\"foo\"}"))
|
||||||
c.Request.Header.Add("Content-Type", MIMEJSON)
|
c.Request.Header.Add("Content-Type", commonB.MIMEJSON)
|
||||||
var obj struct {
|
var obj struct {
|
||||||
Foo string `json:"foo"`
|
Foo string `json:"foo"`
|
||||||
Bar string `json:"bar"`
|
Bar string `json:"bar"`
|
||||||
|
@ -1597,20 +1635,20 @@ func TestContextShouldBindBodyWith(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range []struct {
|
for _, tt := range []struct {
|
||||||
name string
|
name string
|
||||||
bindingA, bindingB binding.BindingBody
|
bindingA, bindingB commonB.BindingBody
|
||||||
bodyA, bodyB string
|
bodyA, bodyB string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "JSON & JSON",
|
name: "JSON & JSON",
|
||||||
bindingA: binding.JSON,
|
bindingA: binding.JSON(),
|
||||||
bindingB: binding.JSON,
|
bindingB: binding.JSON(),
|
||||||
bodyA: `{"foo":"FOO"}`,
|
bodyA: `{"foo":"FOO"}`,
|
||||||
bodyB: `{"bar":"BAR"}`,
|
bodyB: `{"bar":"BAR"}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "JSON & XML",
|
name: "JSON & XML",
|
||||||
bindingA: binding.JSON,
|
bindingA: binding.JSON(),
|
||||||
bindingB: binding.XML,
|
bindingB: binding.XML(),
|
||||||
bodyA: `{"foo":"FOO"}`,
|
bodyA: `{"foo":"FOO"}`,
|
||||||
bodyB: `<?xml version="1.0" encoding="UTF-8"?>
|
bodyB: `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<root>
|
<root>
|
||||||
|
@ -1619,8 +1657,8 @@ func TestContextShouldBindBodyWith(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "XML & XML",
|
name: "XML & XML",
|
||||||
bindingA: binding.XML,
|
bindingA: binding.XML(),
|
||||||
bindingB: binding.XML,
|
bindingB: binding.XML(),
|
||||||
bodyA: `<?xml version="1.0" encoding="UTF-8"?>
|
bodyA: `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<root>
|
<root>
|
||||||
<foo>FOO</foo>
|
<foo>FOO</foo>
|
||||||
|
@ -1718,7 +1756,7 @@ func TestContextGetRawData(t *testing.T) {
|
||||||
c, _ := CreateTestContext(httptest.NewRecorder())
|
c, _ := CreateTestContext(httptest.NewRecorder())
|
||||||
body := bytes.NewBufferString("Fetch binary post data")
|
body := bytes.NewBufferString("Fetch binary post data")
|
||||||
c.Request, _ = http.NewRequest("POST", "/", body)
|
c.Request, _ = http.NewRequest("POST", "/", body)
|
||||||
c.Request.Header.Add("Content-Type", MIMEPOSTForm)
|
c.Request.Header.Add("Content-Type", commonB.MIMEPOSTForm)
|
||||||
|
|
||||||
data, err := c.GetRawData()
|
data, err := c.GetRawData()
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
|
@ -7,12 +7,12 @@ package gin
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BindWith binds the passed struct pointer using the specified binding engine.
|
// BindWith binds the passed struct pointer using the specified binding engine.
|
||||||
// See the binding package.
|
// See the binding package.
|
||||||
func (c *Context) BindWith(obj interface{}, b binding.Binding) error {
|
func (c *Context) BindWith(obj interface{}, b common.Binding) error {
|
||||||
log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to
|
log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to
|
||||||
be deprecated, please check issue #662 and either use MustBindWith() if you
|
be deprecated, please check issue #662 and either use MustBindWith() if you
|
||||||
want HTTP 400 to be automatically returned if any error occur, or use
|
want HTTP 400 to be automatically returned if any error occur, or use
|
||||||
|
|
4
gin.go
4
gin.go
|
@ -13,6 +13,8 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin/render"
|
"github.com/gin-gonic/gin/render"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -417,7 +419,7 @@ func (engine *Engine) handleHTTPRequest(c *Context) {
|
||||||
serveError(c, http.StatusNotFound, default404Body)
|
serveError(c, http.StatusNotFound, default404Body)
|
||||||
}
|
}
|
||||||
|
|
||||||
var mimePlain = []string{MIMEPlain}
|
var mimePlain = []string{common.MIMEPlain}
|
||||||
|
|
||||||
func serveError(c *Context, code int, defaultMessage []byte) {
|
func serveError(c *Context, code int, defaultMessage []byte) {
|
||||||
c.writermem.status = code
|
c.writermem.status = code
|
||||||
|
|
6
mode.go
6
mode.go
|
@ -8,7 +8,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EnvGinMode indicates environment name for gin mode.
|
// EnvGinMode indicates environment name for gin mode.
|
||||||
|
@ -68,13 +68,13 @@ func SetMode(value string) {
|
||||||
|
|
||||||
// DisableBindValidation closes the default validator.
|
// DisableBindValidation closes the default validator.
|
||||||
func DisableBindValidation() {
|
func DisableBindValidation() {
|
||||||
binding.Validator = nil
|
common.Validator = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableJsonDecoderUseNumber sets true for binding.EnableDecoderUseNumberto to
|
// EnableJsonDecoderUseNumber sets true for binding.EnableDecoderUseNumberto to
|
||||||
// call the UseNumber method on the JSON Decoder instance.
|
// call the UseNumber method on the JSON Decoder instance.
|
||||||
func EnableJsonDecoderUseNumber() {
|
func EnableJsonDecoderUseNumber() {
|
||||||
binding.EnableDecoderUseNumber = true
|
common.EnableDecoderUseNumber = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mode returns currently gin mode.
|
// Mode returns currently gin mode.
|
||||||
|
|
14
mode_test.go
14
mode_test.go
|
@ -8,7 +8,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding/common"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,7 +41,15 @@ func TestSetMode(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnableJsonDecoderUseNumber(t *testing.T) {
|
func TestEnableJsonDecoderUseNumber(t *testing.T) {
|
||||||
assert.False(t, binding.EnableDecoderUseNumber)
|
assert.False(t, common.EnableDecoderUseNumber)
|
||||||
EnableJsonDecoderUseNumber()
|
EnableJsonDecoderUseNumber()
|
||||||
assert.True(t, binding.EnableDecoderUseNumber)
|
assert.True(t, common.EnableDecoderUseNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDisableBindValidation(t *testing.T) {
|
||||||
|
bckp := common.Validator
|
||||||
|
assert.NotNil(t, common.Validator)
|
||||||
|
DisableBindValidation()
|
||||||
|
assert.Nil(t, common.Validator)
|
||||||
|
common.Validator = bckp
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
//WriteContentType set the content-type header
|
||||||
|
func WriteContentType(w http.ResponseWriter, value []string) {
|
||||||
|
header := w.Header()
|
||||||
|
if val := header["Content-Type"]; len(val) == 0 {
|
||||||
|
header["Content-Type"] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render interface is to be implemented by JSON, XML, HTML, YAML and so on.
|
||||||
|
type Render interface {
|
||||||
|
// Render writes data with custom ContentType.
|
||||||
|
Render(http.ResponseWriter) error
|
||||||
|
// WriteContentType writes custom ContentType.
|
||||||
|
WriteContentType(w http.ResponseWriter)
|
||||||
|
}
|
||||||
|
|
||||||
|
//List hold the defined render (obj, options)
|
||||||
|
var List = map[string]func(interface{}, map[string]string) Render{}
|
|
@ -4,7 +4,11 @@
|
||||||
|
|
||||||
package render
|
package render
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
|
)
|
||||||
|
|
||||||
// Data contains ContentType and bytes data.
|
// Data contains ContentType and bytes data.
|
||||||
type Data struct {
|
type Data struct {
|
||||||
|
@ -21,5 +25,5 @@ func (r Data) Render(w http.ResponseWriter) (err error) {
|
||||||
|
|
||||||
// WriteContentType (Data) writes custom ContentType.
|
// WriteContentType (Data) writes custom ContentType.
|
||||||
func (r Data) WriteContentType(w http.ResponseWriter) {
|
func (r Data) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, []string{r.ContentType})
|
common.WriteContentType(w, []string{r.ContentType})
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ package render
|
||||||
import (
|
import (
|
||||||
"html/template"
|
"html/template"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Delims represents a set of Left and Right delimiters for HTML template rendering.
|
// Delims represents a set of Left and Right delimiters for HTML template rendering.
|
||||||
|
@ -20,7 +22,7 @@ type Delims struct {
|
||||||
// HTMLRender interface is to be implemented by HTMLProduction and HTMLDebug.
|
// HTMLRender interface is to be implemented by HTMLProduction and HTMLDebug.
|
||||||
type HTMLRender interface {
|
type HTMLRender interface {
|
||||||
// Instance returns an HTML instance.
|
// Instance returns an HTML instance.
|
||||||
Instance(string, interface{}) Render
|
Instance(string, interface{}) HTML
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTMLProduction contains template reference and its delims.
|
// HTMLProduction contains template reference and its delims.
|
||||||
|
@ -47,7 +49,7 @@ type HTML struct {
|
||||||
var htmlContentType = []string{"text/html; charset=utf-8"}
|
var htmlContentType = []string{"text/html; charset=utf-8"}
|
||||||
|
|
||||||
// Instance (HTMLProduction) returns an HTML instance which it realizes Render interface.
|
// Instance (HTMLProduction) returns an HTML instance which it realizes Render interface.
|
||||||
func (r HTMLProduction) Instance(name string, data interface{}) Render {
|
func (r HTMLProduction) Instance(name string, data interface{}) HTML {
|
||||||
return HTML{
|
return HTML{
|
||||||
Template: r.Template,
|
Template: r.Template,
|
||||||
Name: name,
|
Name: name,
|
||||||
|
@ -56,7 +58,7 @@ func (r HTMLProduction) Instance(name string, data interface{}) Render {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instance (HTMLDebug) returns an HTML instance which it realizes Render interface.
|
// Instance (HTMLDebug) returns an HTML instance which it realizes Render interface.
|
||||||
func (r HTMLDebug) Instance(name string, data interface{}) Render {
|
func (r HTMLDebug) Instance(name string, data interface{}) HTML {
|
||||||
return HTML{
|
return HTML{
|
||||||
Template: r.loadTemplate(),
|
Template: r.loadTemplate(),
|
||||||
Name: name,
|
Name: name,
|
||||||
|
@ -88,5 +90,5 @@ func (r HTML) Render(w http.ResponseWriter) error {
|
||||||
|
|
||||||
// WriteContentType (HTML) writes HTML ContentType.
|
// WriteContentType (HTML) writes HTML ContentType.
|
||||||
func (r HTML) WriteContentType(w http.ResponseWriter) {
|
func (r HTML) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, htmlContentType)
|
common.WriteContentType(w, htmlContentType)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package render
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -11,8 +11,42 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin/internal/json"
|
"github.com/gin-gonic/gin/internal/json"
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.List["JSON"] = NewJSON
|
||||||
|
common.List["IndentedJSON"] = NewIndentedJSON
|
||||||
|
common.List["SecureJSON"] = NewSecureJSON
|
||||||
|
common.List["JsonpJSON"] = NewJsonpJSON
|
||||||
|
common.List["AsciiJSON"] = NewAsciiJSON
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewJSON build a new JSON render
|
||||||
|
func NewJSON(obj interface{}, _ map[string]string) common.Render {
|
||||||
|
return JSON{Data: obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewIndentedJSON build a new IndentedJSON render
|
||||||
|
func NewIndentedJSON(obj interface{}, _ map[string]string) common.Render {
|
||||||
|
return IndentedJSON{Data: obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewSecureJSON build a new SecureJSON render
|
||||||
|
func NewSecureJSON(obj interface{}, opts map[string]string) common.Render {
|
||||||
|
return SecureJSON{Prefix: opts["Prefix"], Data: obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewJsonpJSON build a new JsonpJSON render
|
||||||
|
func NewJsonpJSON(obj interface{}, opts map[string]string) common.Render {
|
||||||
|
return JsonpJSON{Callback: opts["Callback"], Data: obj}
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewAsciiJSON build a new AsciiJSON render
|
||||||
|
func NewAsciiJSON(obj interface{}, _ map[string]string) common.Render {
|
||||||
|
return AsciiJSON{Data: obj}
|
||||||
|
}
|
||||||
|
|
||||||
// JSON contains the given interface object.
|
// JSON contains the given interface object.
|
||||||
type JSON struct {
|
type JSON struct {
|
||||||
Data interface{}
|
Data interface{}
|
||||||
|
@ -57,12 +91,12 @@ func (r JSON) Render(w http.ResponseWriter) (err error) {
|
||||||
|
|
||||||
// WriteContentType (JSON) writes JSON ContentType.
|
// WriteContentType (JSON) writes JSON ContentType.
|
||||||
func (r JSON) WriteContentType(w http.ResponseWriter) {
|
func (r JSON) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, jsonContentType)
|
common.WriteContentType(w, jsonContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteJSON marshals the given interface object and writes it with custom ContentType.
|
// WriteJSON marshals the given interface object and writes it with custom ContentType.
|
||||||
func WriteJSON(w http.ResponseWriter, obj interface{}) error {
|
func WriteJSON(w http.ResponseWriter, obj interface{}) error {
|
||||||
writeContentType(w, jsonContentType)
|
common.WriteContentType(w, jsonContentType)
|
||||||
jsonBytes, err := json.Marshal(obj)
|
jsonBytes, err := json.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -84,7 +118,7 @@ func (r IndentedJSON) Render(w http.ResponseWriter) error {
|
||||||
|
|
||||||
// WriteContentType (IndentedJSON) writes JSON ContentType.
|
// WriteContentType (IndentedJSON) writes JSON ContentType.
|
||||||
func (r IndentedJSON) WriteContentType(w http.ResponseWriter) {
|
func (r IndentedJSON) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, jsonContentType)
|
common.WriteContentType(w, jsonContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render (SecureJSON) marshals the given interface object and writes it with custom ContentType.
|
// Render (SecureJSON) marshals the given interface object and writes it with custom ContentType.
|
||||||
|
@ -107,7 +141,7 @@ func (r SecureJSON) Render(w http.ResponseWriter) error {
|
||||||
|
|
||||||
// WriteContentType (SecureJSON) writes JSON ContentType.
|
// WriteContentType (SecureJSON) writes JSON ContentType.
|
||||||
func (r SecureJSON) WriteContentType(w http.ResponseWriter) {
|
func (r SecureJSON) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, jsonContentType)
|
common.WriteContentType(w, jsonContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType.
|
// Render (JsonpJSON) marshals the given interface object and writes it and its callback with custom ContentType.
|
||||||
|
@ -146,7 +180,7 @@ func (r JsonpJSON) Render(w http.ResponseWriter) (err error) {
|
||||||
|
|
||||||
// WriteContentType (JsonpJSON) writes Javascript ContentType.
|
// WriteContentType (JsonpJSON) writes Javascript ContentType.
|
||||||
func (r JsonpJSON) WriteContentType(w http.ResponseWriter) {
|
func (r JsonpJSON) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, jsonpContentType)
|
common.WriteContentType(w, jsonpContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render (AsciiJSON) marshals the given interface object and writes it with custom ContentType.
|
// Render (AsciiJSON) marshals the given interface object and writes it with custom ContentType.
|
||||||
|
@ -172,5 +206,5 @@ func (r AsciiJSON) Render(w http.ResponseWriter) (err error) {
|
||||||
|
|
||||||
// WriteContentType (AsciiJSON) writes JSON ContentType.
|
// WriteContentType (AsciiJSON) writes JSON ContentType.
|
||||||
func (r AsciiJSON) WriteContentType(w http.ResponseWriter) {
|
func (r AsciiJSON) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, jsonAsciiContentType)
|
common.WriteContentType(w, jsonAsciiContentType)
|
||||||
}
|
}
|
|
@ -4,14 +4,24 @@
|
||||||
|
|
||||||
// +build go1.7
|
// +build go1.7
|
||||||
|
|
||||||
package render
|
package json
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin/internal/json"
|
"github.com/gin-gonic/gin/internal/json"
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.List["PureJSON"] = NewPureJSON
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewPureJSON build a new PureJSON render
|
||||||
|
func NewPureJSON(obj interface{}, _ map[string]string) common.Render {
|
||||||
|
return PureJSON{Data: obj}
|
||||||
|
}
|
||||||
|
|
||||||
// PureJSON contains the given interface object.
|
// PureJSON contains the given interface object.
|
||||||
type PureJSON struct {
|
type PureJSON struct {
|
||||||
Data interface{}
|
Data interface{}
|
||||||
|
@ -27,5 +37,5 @@ func (r PureJSON) Render(w http.ResponseWriter) error {
|
||||||
|
|
||||||
// WriteContentType (PureJSON) writes custom ContentType.
|
// WriteContentType (PureJSON) writes custom ContentType.
|
||||||
func (r PureJSON) WriteContentType(w http.ResponseWriter) {
|
func (r PureJSON) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, jsonContentType)
|
common.WriteContentType(w, jsonContentType)
|
||||||
}
|
}
|
|
@ -2,14 +2,19 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package render
|
package msgpack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
"github.com/ugorji/go/codec"
|
"github.com/ugorji/go/codec"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.List["MsgPack"] = NewMsgPack
|
||||||
|
}
|
||||||
|
|
||||||
// MsgPack contains the given interface object.
|
// MsgPack contains the given interface object.
|
||||||
type MsgPack struct {
|
type MsgPack struct {
|
||||||
Data interface{}
|
Data interface{}
|
||||||
|
@ -19,7 +24,7 @@ var msgpackContentType = []string{"application/msgpack; charset=utf-8"}
|
||||||
|
|
||||||
// WriteContentType (MsgPack) writes MsgPack ContentType.
|
// WriteContentType (MsgPack) writes MsgPack ContentType.
|
||||||
func (r MsgPack) WriteContentType(w http.ResponseWriter) {
|
func (r MsgPack) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, msgpackContentType)
|
common.WriteContentType(w, msgpackContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render (MsgPack) encodes the given interface object and writes data with custom ContentType.
|
// Render (MsgPack) encodes the given interface object and writes data with custom ContentType.
|
||||||
|
@ -29,7 +34,12 @@ func (r MsgPack) Render(w http.ResponseWriter) error {
|
||||||
|
|
||||||
// WriteMsgPack writes MsgPack ContentType and encodes the given interface object.
|
// WriteMsgPack writes MsgPack ContentType and encodes the given interface object.
|
||||||
func WriteMsgPack(w http.ResponseWriter, obj interface{}) error {
|
func WriteMsgPack(w http.ResponseWriter, obj interface{}) error {
|
||||||
writeContentType(w, msgpackContentType)
|
common.WriteContentType(w, msgpackContentType)
|
||||||
var mh codec.MsgpackHandle
|
var mh codec.MsgpackHandle
|
||||||
return codec.NewEncoder(w, &mh).Encode(obj)
|
return codec.NewEncoder(w, &mh).Encode(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//NewMsgPack build a new MsgPack render
|
||||||
|
func NewMsgPack(obj interface{}, _ map[string]string) common.Render {
|
||||||
|
return MsgPack{Data: obj}
|
||||||
|
}
|
|
@ -2,14 +2,19 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package render
|
package protobuf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.List["ProtoBuf"] = NewProtoBuf
|
||||||
|
}
|
||||||
|
|
||||||
// ProtoBuf contains the given interface object.
|
// ProtoBuf contains the given interface object.
|
||||||
type ProtoBuf struct {
|
type ProtoBuf struct {
|
||||||
Data interface{}
|
Data interface{}
|
||||||
|
@ -32,5 +37,10 @@ func (r ProtoBuf) Render(w http.ResponseWriter) error {
|
||||||
|
|
||||||
// WriteContentType (ProtoBuf) writes ProtoBuf ContentType.
|
// WriteContentType (ProtoBuf) writes ProtoBuf ContentType.
|
||||||
func (r ProtoBuf) WriteContentType(w http.ResponseWriter) {
|
func (r ProtoBuf) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, protobufContentType)
|
common.WriteContentType(w, protobufContentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewProtoBuf build a new ProtoBuf render
|
||||||
|
func NewProtoBuf(obj interface{}, _ map[string]string) common.Render {
|
||||||
|
return ProtoBuf{Data: obj}
|
||||||
}
|
}
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reader contains the IO reader and its length, and custom ContentType and other headers.
|
// Reader contains the IO reader and its length, and custom ContentType and other headers.
|
||||||
|
@ -29,7 +31,7 @@ func (r Reader) Render(w http.ResponseWriter) (err error) {
|
||||||
|
|
||||||
// WriteContentType (Reader) writes custom ContentType.
|
// WriteContentType (Reader) writes custom ContentType.
|
||||||
func (r Reader) WriteContentType(w http.ResponseWriter) {
|
func (r Reader) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, []string{r.ContentType})
|
common.WriteContentType(w, []string{r.ContentType})
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeHeaders writes custom Header.
|
// writeHeaders writes custom Header.
|
||||||
|
|
100
render/render.go
100
render/render.go
|
@ -4,38 +4,76 @@
|
||||||
|
|
||||||
package render
|
package render
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
// Render interface is to be implemented by JSON, XML, HTML, YAML and so on.
|
"github.com/gin-gonic/gin/render/common"
|
||||||
type Render interface {
|
|
||||||
// Render writes data with custom ContentType.
|
|
||||||
Render(http.ResponseWriter) error
|
|
||||||
// WriteContentType writes custom ContentType.
|
|
||||||
WriteContentType(w http.ResponseWriter)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
_ Render = JSON{}
|
|
||||||
_ Render = IndentedJSON{}
|
|
||||||
_ Render = SecureJSON{}
|
|
||||||
_ Render = JsonpJSON{}
|
|
||||||
_ Render = XML{}
|
|
||||||
_ Render = String{}
|
|
||||||
_ Render = Redirect{}
|
|
||||||
_ Render = Data{}
|
|
||||||
_ Render = HTML{}
|
|
||||||
_ HTMLRender = HTMLDebug{}
|
|
||||||
_ HTMLRender = HTMLProduction{}
|
|
||||||
_ Render = YAML{}
|
|
||||||
_ Render = MsgPack{}
|
|
||||||
_ Render = Reader{}
|
|
||||||
_ Render = AsciiJSON{}
|
|
||||||
_ Render = ProtoBuf{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func writeContentType(w http.ResponseWriter, value []string) {
|
var (
|
||||||
header := w.Header()
|
_ common.Render = String{}
|
||||||
if val := header["Content-Type"]; len(val) == 0 {
|
_ common.Render = Redirect{}
|
||||||
header["Content-Type"] = value
|
_ common.Render = Data{}
|
||||||
}
|
_ common.Render = HTML{}
|
||||||
|
_ HTMLRender = HTMLDebug{}
|
||||||
|
_ HTMLRender = HTMLProduction{}
|
||||||
|
_ common.Render = Reader{}
|
||||||
|
)
|
||||||
|
|
||||||
|
//YAML return the render for yaml if loaded
|
||||||
|
func YAML(obj interface{}) common.Render {
|
||||||
|
return retRender("YAML", obj, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//XML return the render for xml if loaded
|
||||||
|
func XML(obj interface{}) common.Render {
|
||||||
|
return retRender("XML", obj, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//ProtoBuf return the render for ProtoBuf if loaded
|
||||||
|
func ProtoBuf(obj interface{}) common.Render {
|
||||||
|
return retRender("ProtoBuf", obj, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//MsgPack return the render for MsgPack if loaded
|
||||||
|
func MsgPack(obj interface{}) common.Render {
|
||||||
|
return retRender("MsgPack", obj, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//JSON return the render for JSON if loaded
|
||||||
|
func JSON(obj interface{}) common.Render {
|
||||||
|
return retRender("JSON", obj, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//IndentedJSON return the render for IndentedJSON if loaded
|
||||||
|
func IndentedJSON(obj interface{}) common.Render {
|
||||||
|
return retRender("IndentedJSON", obj, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//SecureJSON return the render for SecureJSON if loaded
|
||||||
|
func SecureJSON(prefix string, obj interface{}) common.Render {
|
||||||
|
return retRender("SecureJSON", obj, map[string]string{
|
||||||
|
"Prefix": prefix,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//JsonpJSON return the render for JsonpJSON if loaded
|
||||||
|
func JsonpJSON(callback string, obj interface{}) common.Render {
|
||||||
|
return retRender("JsonpJSON", obj, map[string]string{
|
||||||
|
"Callback": callback,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//AsciiJSON return the render for AsciiJSON if loaded
|
||||||
|
func AsciiJSON(obj interface{}) common.Render {
|
||||||
|
return retRender("AsciiJSON", obj, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Search for a render
|
||||||
|
func retRender(rID string, obj interface{}, opts map[string]string) common.Render {
|
||||||
|
r, ok := common.List[rID]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("Undefined render %s", rID))
|
||||||
|
}
|
||||||
|
return r(obj, opts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package render
|
||||||
|
|
||||||
|
import "github.com/gin-gonic/gin/render/common"
|
||||||
|
|
||||||
|
//PureJSON return the render for AsciiJSON if loaded
|
||||||
|
func PureJSON(obj interface{}) common.Render {
|
||||||
|
return retRender("PureJSON", obj, nil)
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ func TestRenderPureJSON(t *testing.T) {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"html": "<b>",
|
"html": "<b>",
|
||||||
}
|
}
|
||||||
err := (PureJSON{data}).Render(w)
|
err := PureJSON(data).Render(w)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"<b>\"}\n", w.Body.String())
|
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"<b>\"}\n", w.Body.String())
|
||||||
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
|
|
@ -20,6 +20,12 @@ import (
|
||||||
"github.com/ugorji/go/codec"
|
"github.com/ugorji/go/codec"
|
||||||
|
|
||||||
testdata "github.com/gin-gonic/gin/testdata/protoexample"
|
testdata "github.com/gin-gonic/gin/testdata/protoexample"
|
||||||
|
|
||||||
|
_ "github.com/gin-gonic/gin/render/json"
|
||||||
|
_ "github.com/gin-gonic/gin/render/msgpack"
|
||||||
|
_ "github.com/gin-gonic/gin/render/protobuf"
|
||||||
|
_ "github.com/gin-gonic/gin/render/xml"
|
||||||
|
_ "github.com/gin-gonic/gin/render/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO unit tests
|
// TODO unit tests
|
||||||
|
@ -31,10 +37,10 @@ func TestRenderMsgPack(t *testing.T) {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
}
|
}
|
||||||
|
|
||||||
(MsgPack{data}).WriteContentType(w)
|
MsgPack(data).WriteContentType(w)
|
||||||
assert.Equal(t, "application/msgpack; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/msgpack; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
|
||||||
err := (MsgPack{data}).Render(w)
|
err := MsgPack(data).Render(w)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
@ -56,10 +62,10 @@ func TestRenderJSON(t *testing.T) {
|
||||||
"html": "<b>",
|
"html": "<b>",
|
||||||
}
|
}
|
||||||
|
|
||||||
(JSON{data}).WriteContentType(w)
|
JSON(data).WriteContentType(w)
|
||||||
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/json; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
|
||||||
err := (JSON{data}).Render(w)
|
err := JSON(data).Render(w)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String())
|
assert.Equal(t, "{\"foo\":\"bar\",\"html\":\"\\u003cb\\u003e\"}", w.Body.String())
|
||||||
|
@ -71,7 +77,7 @@ func TestRenderJSONPanics(t *testing.T) {
|
||||||
data := make(chan int)
|
data := make(chan int)
|
||||||
|
|
||||||
// json: unsupported type: chan int
|
// json: unsupported type: chan int
|
||||||
assert.Panics(t, func() { assert.NoError(t, (JSON{data}).Render(w)) })
|
assert.Panics(t, func() { assert.NoError(t, JSON(data).Render(w)) })
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRenderIndentedJSON(t *testing.T) {
|
func TestRenderIndentedJSON(t *testing.T) {
|
||||||
|
@ -81,7 +87,7 @@ func TestRenderIndentedJSON(t *testing.T) {
|
||||||
"bar": "foo",
|
"bar": "foo",
|
||||||
}
|
}
|
||||||
|
|
||||||
err := (IndentedJSON{data}).Render(w)
|
err := IndentedJSON(data).Render(w)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}", w.Body.String())
|
assert.Equal(t, "{\n \"bar\": \"foo\",\n \"foo\": \"bar\"\n}", w.Body.String())
|
||||||
|
@ -93,7 +99,7 @@ func TestRenderIndentedJSONPanics(t *testing.T) {
|
||||||
data := make(chan int)
|
data := make(chan int)
|
||||||
|
|
||||||
// json: unsupported type: chan int
|
// json: unsupported type: chan int
|
||||||
err := (IndentedJSON{data}).Render(w)
|
err := IndentedJSON(data).Render(w)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,10 +109,10 @@ func TestRenderSecureJSON(t *testing.T) {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
}
|
}
|
||||||
|
|
||||||
(SecureJSON{"while(1);", data}).WriteContentType(w1)
|
SecureJSON("while(1);", data).WriteContentType(w1)
|
||||||
assert.Equal(t, "application/json; charset=utf-8", w1.Header().Get("Content-Type"))
|
assert.Equal(t, "application/json; charset=utf-8", w1.Header().Get("Content-Type"))
|
||||||
|
|
||||||
err1 := (SecureJSON{"while(1);", data}).Render(w1)
|
err1 := SecureJSON("while(1);", data).Render(w1)
|
||||||
|
|
||||||
assert.NoError(t, err1)
|
assert.NoError(t, err1)
|
||||||
assert.Equal(t, "{\"foo\":\"bar\"}", w1.Body.String())
|
assert.Equal(t, "{\"foo\":\"bar\"}", w1.Body.String())
|
||||||
|
@ -119,7 +125,7 @@ func TestRenderSecureJSON(t *testing.T) {
|
||||||
"bar": "foo",
|
"bar": "foo",
|
||||||
}}
|
}}
|
||||||
|
|
||||||
err2 := (SecureJSON{"while(1);", datas}).Render(w2)
|
err2 := SecureJSON("while(1);", datas).Render(w2)
|
||||||
assert.NoError(t, err2)
|
assert.NoError(t, err2)
|
||||||
assert.Equal(t, "while(1);[{\"foo\":\"bar\"},{\"bar\":\"foo\"}]", w2.Body.String())
|
assert.Equal(t, "while(1);[{\"foo\":\"bar\"},{\"bar\":\"foo\"}]", w2.Body.String())
|
||||||
assert.Equal(t, "application/json; charset=utf-8", w2.Header().Get("Content-Type"))
|
assert.Equal(t, "application/json; charset=utf-8", w2.Header().Get("Content-Type"))
|
||||||
|
@ -130,7 +136,7 @@ func TestRenderSecureJSONFail(t *testing.T) {
|
||||||
data := make(chan int)
|
data := make(chan int)
|
||||||
|
|
||||||
// json: unsupported type: chan int
|
// json: unsupported type: chan int
|
||||||
err := (SecureJSON{"while(1);", data}).Render(w)
|
err := SecureJSON("while(1);", data).Render(w)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,10 +146,10 @@ func TestRenderJsonpJSON(t *testing.T) {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
}
|
}
|
||||||
|
|
||||||
(JsonpJSON{"x", data}).WriteContentType(w1)
|
JsonpJSON("x", data).WriteContentType(w1)
|
||||||
assert.Equal(t, "application/javascript; charset=utf-8", w1.Header().Get("Content-Type"))
|
assert.Equal(t, "application/javascript; charset=utf-8", w1.Header().Get("Content-Type"))
|
||||||
|
|
||||||
err1 := (JsonpJSON{"x", data}).Render(w1)
|
err1 := JsonpJSON("x", data).Render(w1)
|
||||||
|
|
||||||
assert.NoError(t, err1)
|
assert.NoError(t, err1)
|
||||||
assert.Equal(t, "x({\"foo\":\"bar\"})", w1.Body.String())
|
assert.Equal(t, "x({\"foo\":\"bar\"})", w1.Body.String())
|
||||||
|
@ -156,7 +162,7 @@ func TestRenderJsonpJSON(t *testing.T) {
|
||||||
"bar": "foo",
|
"bar": "foo",
|
||||||
}}
|
}}
|
||||||
|
|
||||||
err2 := (JsonpJSON{"x", datas}).Render(w2)
|
err2 := JsonpJSON("x", datas).Render(w2)
|
||||||
assert.NoError(t, err2)
|
assert.NoError(t, err2)
|
||||||
assert.Equal(t, "x([{\"foo\":\"bar\"},{\"bar\":\"foo\"}])", w2.Body.String())
|
assert.Equal(t, "x([{\"foo\":\"bar\"},{\"bar\":\"foo\"}])", w2.Body.String())
|
||||||
assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type"))
|
assert.Equal(t, "application/javascript; charset=utf-8", w2.Header().Get("Content-Type"))
|
||||||
|
@ -167,10 +173,10 @@ func TestRenderJsonpJSONError2(t *testing.T) {
|
||||||
data := map[string]interface{}{
|
data := map[string]interface{}{
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
}
|
}
|
||||||
(JsonpJSON{"", data}).WriteContentType(w)
|
JsonpJSON("", data).WriteContentType(w)
|
||||||
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/javascript; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
|
||||||
e := (JsonpJSON{"", data}).Render(w)
|
e := JsonpJSON("", data).Render(w)
|
||||||
assert.NoError(t, e)
|
assert.NoError(t, e)
|
||||||
|
|
||||||
assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
|
assert.Equal(t, "{\"foo\":\"bar\"}", w.Body.String())
|
||||||
|
@ -182,7 +188,7 @@ func TestRenderJsonpJSONFail(t *testing.T) {
|
||||||
data := make(chan int)
|
data := make(chan int)
|
||||||
|
|
||||||
// json: unsupported type: chan int
|
// json: unsupported type: chan int
|
||||||
err := (JsonpJSON{"x", data}).Render(w)
|
err := JsonpJSON("x", data).Render(w)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +199,7 @@ func TestRenderAsciiJSON(t *testing.T) {
|
||||||
"tag": "<br>",
|
"tag": "<br>",
|
||||||
}
|
}
|
||||||
|
|
||||||
err := (AsciiJSON{data1}).Render(w1)
|
err := AsciiJSON(data1).Render(w1)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "{\"lang\":\"GO\\u8bed\\u8a00\",\"tag\":\"\\u003cbr\\u003e\"}", w1.Body.String())
|
assert.Equal(t, "{\"lang\":\"GO\\u8bed\\u8a00\",\"tag\":\"\\u003cbr\\u003e\"}", w1.Body.String())
|
||||||
|
@ -202,7 +208,7 @@ func TestRenderAsciiJSON(t *testing.T) {
|
||||||
w2 := httptest.NewRecorder()
|
w2 := httptest.NewRecorder()
|
||||||
data2 := float64(3.1415926)
|
data2 := float64(3.1415926)
|
||||||
|
|
||||||
err = (AsciiJSON{data2}).Render(w2)
|
err = AsciiJSON(data2).Render(w2)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "3.1415926", w2.Body.String())
|
assert.Equal(t, "3.1415926", w2.Body.String())
|
||||||
}
|
}
|
||||||
|
@ -212,7 +218,7 @@ func TestRenderAsciiJSONFail(t *testing.T) {
|
||||||
data := make(chan int)
|
data := make(chan int)
|
||||||
|
|
||||||
// json: unsupported type: chan int
|
// json: unsupported type: chan int
|
||||||
assert.Error(t, (AsciiJSON{data}).Render(w))
|
assert.Error(t, AsciiJSON(data).Render(w))
|
||||||
}
|
}
|
||||||
|
|
||||||
type xmlmap map[string]interface{}
|
type xmlmap map[string]interface{}
|
||||||
|
@ -247,10 +253,10 @@ b:
|
||||||
c: 2
|
c: 2
|
||||||
d: [3, 4]
|
d: [3, 4]
|
||||||
`
|
`
|
||||||
(YAML{data}).WriteContentType(w)
|
YAML(data).WriteContentType(w)
|
||||||
assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
|
||||||
err := (YAML{data}).Render(w)
|
err := YAML(data).Render(w)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "\"\\na : Easy!\\nb:\\n\\tc: 2\\n\\td: [3, 4]\\n\\t\"\n", w.Body.String())
|
assert.Equal(t, "\"\\na : Easy!\\nb:\\n\\tc: 2\\n\\td: [3, 4]\\n\\t\"\n", w.Body.String())
|
||||||
assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
@ -265,7 +271,7 @@ func (ft *fail) MarshalYAML() (interface{}, error) {
|
||||||
|
|
||||||
func TestRenderYAMLFail(t *testing.T) {
|
func TestRenderYAMLFail(t *testing.T) {
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
err := (YAML{&fail{}}).Render(w)
|
err := YAML(&fail{}).Render(w)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,12 +285,12 @@ func TestRenderProtoBuf(t *testing.T) {
|
||||||
Reps: reps,
|
Reps: reps,
|
||||||
}
|
}
|
||||||
|
|
||||||
(ProtoBuf{data}).WriteContentType(w)
|
ProtoBuf(data).WriteContentType(w)
|
||||||
protoData, err := proto.Marshal(data)
|
protoData, err := proto.Marshal(data)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))
|
||||||
|
|
||||||
err = (ProtoBuf{data}).Render(w)
|
err = ProtoBuf(data).Render(w)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, string(protoData), w.Body.String())
|
assert.Equal(t, string(protoData), w.Body.String())
|
||||||
|
@ -294,7 +300,7 @@ func TestRenderProtoBuf(t *testing.T) {
|
||||||
func TestRenderProtoBufFail(t *testing.T) {
|
func TestRenderProtoBufFail(t *testing.T) {
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
data := &testdata.Test{}
|
data := &testdata.Test{}
|
||||||
err := (ProtoBuf{data}).Render(w)
|
err := ProtoBuf(data).Render(w)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,10 +310,10 @@ func TestRenderXML(t *testing.T) {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
}
|
}
|
||||||
|
|
||||||
(XML{data}).WriteContentType(w)
|
XML(data).WriteContentType(w)
|
||||||
assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type"))
|
assert.Equal(t, "application/xml; charset=utf-8", w.Header().Get("Content-Type"))
|
||||||
|
|
||||||
err := (XML{data}).Render(w)
|
err := XML(data).Render(w)
|
||||||
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String())
|
assert.Equal(t, "<map><foo>bar</foo></map>", w.Body.String())
|
||||||
|
@ -486,3 +492,14 @@ func TestRenderReader(t *testing.T) {
|
||||||
assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition"))
|
assert.Equal(t, headers["Content-Disposition"], w.Header().Get("Content-Disposition"))
|
||||||
assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id"))
|
assert.Equal(t, headers["x-request-id"], w.Header().Get("x-request-id"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRenderPanic(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Errorf("retRender did not panic")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
//Should panic
|
||||||
|
retRender("NotKnowRender", nil, nil)
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// String contains the given interface object slice and its format.
|
// String contains the given interface object slice and its format.
|
||||||
|
@ -25,12 +27,12 @@ func (r String) Render(w http.ResponseWriter) error {
|
||||||
|
|
||||||
// WriteContentType (String) writes Plain ContentType.
|
// WriteContentType (String) writes Plain ContentType.
|
||||||
func (r String) WriteContentType(w http.ResponseWriter) {
|
func (r String) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, plainContentType)
|
common.WriteContentType(w, plainContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteString writes data according to its format and write custom ContentType.
|
// WriteString writes data according to its format and write custom ContentType.
|
||||||
func WriteString(w http.ResponseWriter, format string, data []interface{}) (err error) {
|
func WriteString(w http.ResponseWriter, format string, data []interface{}) (err error) {
|
||||||
writeContentType(w, plainContentType)
|
common.WriteContentType(w, plainContentType)
|
||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
_, err = fmt.Fprintf(w, format, data...)
|
_, err = fmt.Fprintf(w, format, data...)
|
||||||
return
|
return
|
||||||
|
|
|
@ -2,13 +2,19 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package render
|
package xml
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.List["XML"] = NewXML
|
||||||
|
}
|
||||||
|
|
||||||
// XML contains the given interface object.
|
// XML contains the given interface object.
|
||||||
type XML struct {
|
type XML struct {
|
||||||
Data interface{}
|
Data interface{}
|
||||||
|
@ -24,5 +30,10 @@ func (r XML) Render(w http.ResponseWriter) error {
|
||||||
|
|
||||||
// WriteContentType (XML) writes XML ContentType for response.
|
// WriteContentType (XML) writes XML ContentType for response.
|
||||||
func (r XML) WriteContentType(w http.ResponseWriter) {
|
func (r XML) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, xmlContentType)
|
common.WriteContentType(w, xmlContentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewXML build a new xml render
|
||||||
|
func NewXML(obj interface{}, _ map[string]string) common.Render {
|
||||||
|
return XML{Data: obj}
|
||||||
}
|
}
|
|
@ -2,14 +2,19 @@
|
||||||
// Use of this source code is governed by a MIT style
|
// Use of this source code is governed by a MIT style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package render
|
package yaml
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/render/common"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
common.List["YAML"] = NewYAML
|
||||||
|
}
|
||||||
|
|
||||||
// YAML contains the given interface object.
|
// YAML contains the given interface object.
|
||||||
type YAML struct {
|
type YAML struct {
|
||||||
Data interface{}
|
Data interface{}
|
||||||
|
@ -32,5 +37,10 @@ func (r YAML) Render(w http.ResponseWriter) error {
|
||||||
|
|
||||||
// WriteContentType (YAML) writes YAML ContentType for response.
|
// WriteContentType (YAML) writes YAML ContentType for response.
|
||||||
func (r YAML) WriteContentType(w http.ResponseWriter) {
|
func (r YAML) WriteContentType(w http.ResponseWriter) {
|
||||||
writeContentType(w, yamlContentType)
|
common.WriteContentType(w, yamlContentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
//NewYAML build a new yaml render
|
||||||
|
func NewYAML(obj interface{}, _ map[string]string) common.Render {
|
||||||
|
return YAML{Data: obj}
|
||||||
}
|
}
|
Loading…
Reference in New Issue