Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,26 @@ func (c *Context) ShouldBindBodyWith(obj any, bb binding.BindingBody) (err error
return bb.BindBody(body, obj)
}

// ShouldBindBodyWithJSON is a shortcut for c.ShouldBindBodyWith(obj, binding.JSON).
func (c *Context) ShouldBindBodyWithJSON(obj any) error {
return c.ShouldBindBodyWith(obj, binding.JSON)
}

// ShouldBindBodyWithXML is a shortcut for c.ShouldBindBodyWith(obj, binding.XML).
func (c *Context) ShouldBindBodyWithXML(obj any) error {
return c.ShouldBindBodyWith(obj, binding.XML)
}

// ShouldBindBodyWithYAML is a shortcut for c.ShouldBindBodyWith(obj, binding.YAML).
func (c *Context) ShouldBindBodyWithYAML(obj any) error {
return c.ShouldBindBodyWith(obj, binding.YAML)
}

// ShouldBindBodyWithTOML is a shortcut for c.ShouldBindBodyWith(obj, binding.TOML).
func (c *Context) ShouldBindBodyWithTOML(obj any) error {
return c.ShouldBindBodyWith(obj, binding.TOML)
}

// ClientIP implements one best effort algorithm to return the real client IP.
// It calls c.RemoteIP() under the hood, to check if the remote IP is a trusted proxy or not.
// If it is it will then try to parse the headers defined in Engine.RemoteIPHeaders (defaulting to [X-Forwarded-For, X-Real-Ip]).
Expand Down
257 changes: 257 additions & 0 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1975,6 +1975,263 @@ func TestContextShouldBindBodyWith(t *testing.T) {
}
}

func TestContextShouldBindBodyWithJSON(t *testing.T) {
for _, tt := range []struct {
name string
bindingBody binding.BindingBody
body string
}{
{
name: " JSON & JSON-BODY ",
bindingBody: binding.JSON,
body: `{"foo":"FOO"}`,
},
{
name: " JSON & XML-BODY ",
bindingBody: binding.XML,
body: `<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo>FOO</foo>
</root>`,
},
{
name: " JSON & YAML-BODY ",
bindingBody: binding.YAML,
body: `foo: FOO`,
},
{
name: " JSON & TOM-BODY ",
bindingBody: binding.TOML,
body: `foo=FOO`,
},
} {
t.Logf("testing: %s", tt.name)

w := httptest.NewRecorder()
c, _ := CreateTestContext(w)

c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(tt.body))

type typeJSON struct {
Foo string `json:"foo" binding:"required"`
}
objJSON := typeJSON{}

if tt.bindingBody == binding.JSON {
assert.NoError(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{"FOO"}, objJSON)
}

if tt.bindingBody == binding.XML {
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{}, objJSON)
}

if tt.bindingBody == binding.YAML {
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{}, objJSON)
}

if tt.bindingBody == binding.TOML {
assert.Error(t, c.ShouldBindBodyWithJSON(&objJSON))
assert.Equal(t, typeJSON{}, objJSON)
}
}
}

func TestContextShouldBindBodyWithXML(t *testing.T) {
for _, tt := range []struct {
name string
bindingBody binding.BindingBody
body string
}{
{
name: " XML & JSON-BODY ",
bindingBody: binding.JSON,
body: `{"foo":"FOO"}`,
},
{
name: " XML & XML-BODY ",
bindingBody: binding.XML,
body: `<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo>FOO</foo>
</root>`,
},
{
name: " XML & YAML-BODY ",
bindingBody: binding.YAML,
body: `foo: FOO`,
},
{
name: " XML & TOM-BODY ",
bindingBody: binding.TOML,
body: `foo=FOO`,
},
} {
t.Logf("testing: %s", tt.name)

w := httptest.NewRecorder()
c, _ := CreateTestContext(w)

c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(tt.body))

type typeXML struct {
Foo string `xml:"foo" binding:"required"`
}
objXML := typeXML{}

if tt.bindingBody == binding.JSON {
assert.Error(t, c.ShouldBindBodyWithXML(&objXML))
assert.Equal(t, typeXML{}, objXML)
}

if tt.bindingBody == binding.XML {
assert.NoError(t, c.ShouldBindBodyWithXML(&objXML))
assert.Equal(t, typeXML{"FOO"}, objXML)
}

if tt.bindingBody == binding.YAML {
assert.Error(t, c.ShouldBindBodyWithXML(&objXML))
assert.Equal(t, typeXML{}, objXML)
}

if tt.bindingBody == binding.TOML {
assert.Error(t, c.ShouldBindBodyWithXML(&objXML))
assert.Equal(t, typeXML{}, objXML)
}
}
}

func TestContextShouldBindBodyWithYAML(t *testing.T) {
for _, tt := range []struct {
name string
bindingBody binding.BindingBody
body string
}{
{
name: " YAML & JSON-BODY ",
bindingBody: binding.JSON,
body: `{"foo":"FOO"}`,
},
{
name: " YAML & XML-BODY ",
bindingBody: binding.XML,
body: `<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo>FOO</foo>
</root>`,
},
{
name: " YAML & YAML-BODY ",
bindingBody: binding.YAML,
body: `foo: FOO`,
},
{
name: " YAML & TOM-BODY ",
bindingBody: binding.TOML,
body: `foo=FOO`,
},
} {
t.Logf("testing: %s", tt.name)

w := httptest.NewRecorder()
c, _ := CreateTestContext(w)

c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(tt.body))

type typeYAML struct {
Foo string `yaml:"foo" binding:"required"`
}
objYAML := typeYAML{}

// YAML belongs to a super collection of JSON, so JSON can be parsed by YAML
if tt.bindingBody == binding.JSON {
assert.NoError(t, c.ShouldBindBodyWithYAML(&objYAML))
assert.Equal(t, typeYAML{"FOO"}, objYAML)
}

if tt.bindingBody == binding.XML {
assert.Error(t, c.ShouldBindBodyWithYAML(&objYAML))
assert.Equal(t, typeYAML{}, objYAML)
}

if tt.bindingBody == binding.YAML {
assert.NoError(t, c.ShouldBindBodyWithYAML(&objYAML))
assert.Equal(t, typeYAML{"FOO"}, objYAML)
}

if tt.bindingBody == binding.TOML {
assert.Error(t, c.ShouldBindBodyWithYAML(&objYAML))
assert.Equal(t, typeYAML{}, objYAML)
}
}
}

func TestContextShouldBindBodyWithTOML(t *testing.T) {
for _, tt := range []struct {
name string
bindingBody binding.BindingBody
body string
}{
{
name: " TOML & JSON-BODY ",
bindingBody: binding.JSON,
body: `{"foo":"FOO"}`,
},
{
name: " TOML & XML-BODY ",
bindingBody: binding.XML,
body: `<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo>FOO</foo>
</root>`,
},
{
name: " TOML & YAML-BODY ",
bindingBody: binding.YAML,
body: `foo: FOO`,
},
{
name: " TOML & TOM-BODY ",
bindingBody: binding.TOML,
body: `foo = 'FOO'`,
},
} {
t.Logf("testing: %s", tt.name)

w := httptest.NewRecorder()
c, _ := CreateTestContext(w)

c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString(tt.body))

type typeTOML struct {
Foo string `toml:"foo" binding:"required"`
}
objTOML := typeTOML{}

if tt.bindingBody == binding.JSON {
assert.Error(t, c.ShouldBindBodyWithTOML(&objTOML))
assert.Equal(t, typeTOML{}, objTOML)
}

if tt.bindingBody == binding.XML {
assert.Error(t, c.ShouldBindBodyWithTOML(&objTOML))
assert.Equal(t, typeTOML{}, objTOML)
}

if tt.bindingBody == binding.YAML {
assert.Error(t, c.ShouldBindBodyWithTOML(&objTOML))
assert.Equal(t, typeTOML{}, objTOML)
}

if tt.bindingBody == binding.TOML {
assert.NoError(t, c.ShouldBindBodyWithTOML(&objTOML))
assert.Equal(t, typeTOML{"FOO"}, objTOML)
}
}
}

func TestContextGolangContext(t *testing.T) {
c, _ := CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest("POST", "/", bytes.NewBufferString("{\"foo\":\"bar\", \"bar\":\"foo\"}"))
Expand Down
9 changes: 7 additions & 2 deletions docs/doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -1956,7 +1956,12 @@ func SomeHandler(c *gin.Context) {
}
```

For this, you can use `c.ShouldBindBodyWith`.
For this, you can use `c.ShouldBindBodyWith` or shortcuts.

- `c.ShouldBindBodyWithJSON` is a shortcut for c.ShouldBindBodyWith(obj, binding.JSON).
- `c.ShouldBindBodyWithXML` is a shortcut for c.ShouldBindBodyWith(obj, binding.XML).
- `c.ShouldBindBodyWithYAML` is a shortcut for c.ShouldBindBodyWith(obj, binding.YAML).
- `c.ShouldBindBodyWithTOML` is a shortcut for c.ShouldBindBodyWith(obj, binding.TOML).

```go
func SomeHandler(c *gin.Context) {
Expand All @@ -1969,7 +1974,7 @@ func SomeHandler(c *gin.Context) {
} else if errB := c.ShouldBindBodyWith(&objB, binding.JSON); errB == nil {
c.String(http.StatusOK, `the body should be formB JSON`)
// And it can accepts other formats
} else if errB2 := c.ShouldBindBodyWith(&objB, binding.XML); errB2 == nil {
} else if errB2 := c.ShouldBindBodyWithXML(&objB); errB2 == nil {
c.String(http.StatusOK, `the body should be formB XML`)
} else {
...
Expand Down