Merge 22ae924b10f959da8fcd360b84281553f03f633a into c3d1092b3b48addf6f9cd00fe274ec3bd14650eb

This commit is contained in:
Kristian Köhler 2025-10-11 21:19:01 +08:00 committed by GitHub
commit 823fb36ba1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 84 additions and 14 deletions

View File

@ -1280,32 +1280,64 @@ type Negotiate struct {
TOMLData any
}
// Negotiate calls different Render according to acceptable Accept format.
func (c *Context) Negotiate(code int, config Negotiate) {
switch c.NegotiateFormat(config.Offered...) {
case binding.MIMEJSON:
func NewNegotiate(offered []string) Negotiate {
return Negotiate{Offered: offered}
}
func (receiver Negotiate) WithData(data any) Negotiate {
receiver.Data = data
return receiver
}
// NegotiationRenderFunc is responsible for rendering data in a specific format.
type NegotiationRenderFunc func(status int, config Negotiate, c *Context)
func AddNegotiationRenderMapping(mimeType string, binding NegotiationRenderFunc) {
negotiationRenderMappings[mimeType] = binding
}
// All predefined negotiationRenderMappings - associate a content type
// with a NegotiationRenderFunc, which is responsible for rendering
// data in a specific format.
var negotiationRenderMappings = map[string]NegotiationRenderFunc{
binding.MIMEJSON: func(code int, config Negotiate, c *Context) {
data := chooseData(config.JSONData, config.Data)
c.JSON(code, data)
case binding.MIMEHTML:
},
binding.MIMEHTML: func(code int, config Negotiate, c *Context) {
data := chooseData(config.HTMLData, config.Data)
c.HTML(code, config.HTMLName, data)
case binding.MIMEXML:
},
binding.MIMEXML: func(code int, config Negotiate, c *Context) {
data := chooseData(config.XMLData, config.Data)
c.XML(code, data)
case binding.MIMEYAML, binding.MIMEYAML2:
},
binding.MIMEYAML: func(code int, config Negotiate, c *Context) {
data := chooseData(config.YAMLData, config.Data)
c.YAML(code, data)
case binding.MIMETOML:
},
binding.MIMEYAML2: func(code int, config Negotiate, c *Context) {
data := chooseData(config.YAMLData, config.Data)
c.YAML(code, data)
},
binding.MIMETOML: func(code int, config Negotiate, c *Context) {
data := chooseData(config.TOMLData, config.Data)
c.TOML(code, data)
},
binding.MIMEPROTOBUF: func(code int, config Negotiate, c *Context) {
c.ProtoBuf(code, config.Data)
},
}
default:
c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) //nolint: errcheck
// Negotiate calls different Render according to acceptable Accept format.
func (c *Context) Negotiate(code int, config Negotiate) {
accepted := c.NegotiateFormat(config.Offered...)
if fn, ok := negotiationRenderMappings[accepted]; ok {
fn(code, config, c)
return
}
c.AbortWithError(http.StatusNotAcceptable, errors.New("the accepted formats are not offered by the server")) //nolint: errcheck
}
// NegotiateFormat returns an acceptable Accept format.

View File

@ -1615,6 +1615,44 @@ func TestContextNegotiationWithHTML(t *testing.T) {
assert.Equal(t, "text/html; charset=utf-8", w.Header().Get("Content-Type"))
}
func TestContextNegotiationWithProto(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest(http.MethodPost, "", nil)
c.Negotiate(http.StatusOK, Negotiate{
Offered: []string{binding.MIMEPROTOBUF},
Data: &testdata.Test{},
})
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, 0, w.Body.Len())
assert.Equal(t, "application/x-protobuf", w.Header().Get("Content-Type"))
}
func TestContextNegotiationWithCustom(t *testing.T) {
contentType := "application/whatever"
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)
c.Request, _ = http.NewRequest(http.MethodPost, "", nil)
AddNegotiationRenderMapping(contentType, func(status int, config Negotiate, c *Context) {
data := config.Data.([]byte)
c.Data(status, contentType, data)
})
c.Negotiate(http.StatusOK, Negotiate{
Offered: []string{contentType},
Data: []byte("Hello World"),
})
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "Hello World", w.Body.String())
assert.Equal(t, contentType, w.Header().Get("Content-Type"))
}
func TestContextNegotiationNotSupport(t *testing.T) {
w := httptest.NewRecorder()
c, _ := CreateTestContext(w)