chore(header): Add support for RFC 9512: application/yaml (#3851)

* fix(binding): support application/yaml

RFC 9512 defines application/yaml as the official YAML MIME type.
application/x-yaml is deprecated. In this commit, we ensure it is
recognized correctly in Content-Type.

* fix(render): use application/yaml when rendering YAML

As per RFC 9512, application/x-yaml is now deprecated and applications
should use application/yaml. This commit fix the Content-Type header
when rendering YAML.
This commit is contained in:
Vincent Bernat 2024-03-05 14:54:35 +01:00 committed by GitHub
parent ae15646aba
commit 9c61295efe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 12 additions and 8 deletions

View File

@ -21,6 +21,7 @@ const (
MIMEMSGPACK = "application/x-msgpack" MIMEMSGPACK = "application/x-msgpack"
MIMEMSGPACK2 = "application/msgpack" MIMEMSGPACK2 = "application/msgpack"
MIMEYAML = "application/x-yaml" MIMEYAML = "application/x-yaml"
MIMEYAML2 = "application/yaml"
MIMETOML = "application/toml" MIMETOML = "application/toml"
) )
@ -102,7 +103,7 @@ func Default(method, contentType string) Binding {
return ProtoBuf return ProtoBuf
case MIMEMSGPACK, MIMEMSGPACK2: case MIMEMSGPACK, MIMEMSGPACK2:
return MsgPack return MsgPack
case MIMEYAML: case MIMEYAML, MIMEYAML2:
return YAML return YAML
case MIMETOML: case MIMETOML:
return TOML return TOML

View File

@ -19,6 +19,7 @@ const (
MIMEMultipartPOSTForm = "multipart/form-data" MIMEMultipartPOSTForm = "multipart/form-data"
MIMEPROTOBUF = "application/x-protobuf" MIMEPROTOBUF = "application/x-protobuf"
MIMEYAML = "application/x-yaml" MIMEYAML = "application/x-yaml"
MIMEYAML2 = "application/yaml"
MIMETOML = "application/toml" MIMETOML = "application/toml"
) )
@ -96,7 +97,7 @@ func Default(method, contentType string) Binding {
return XML return XML
case MIMEPROTOBUF: case MIMEPROTOBUF:
return ProtoBuf return ProtoBuf
case MIMEYAML: case MIMEYAML, MIMEYAML2:
return YAML return YAML
case MIMEMultipartPOSTForm: case MIMEMultipartPOSTForm:
return FormMultipart return FormMultipart

View File

@ -164,6 +164,8 @@ func TestBindingDefault(t *testing.T) {
assert.Equal(t, YAML, Default("POST", MIMEYAML)) assert.Equal(t, YAML, Default("POST", MIMEYAML))
assert.Equal(t, YAML, Default("PUT", MIMEYAML)) assert.Equal(t, YAML, Default("PUT", MIMEYAML))
assert.Equal(t, YAML, Default("POST", MIMEYAML2))
assert.Equal(t, YAML, Default("PUT", MIMEYAML2))
assert.Equal(t, TOML, Default("POST", MIMETOML)) assert.Equal(t, TOML, Default("POST", MIMETOML))
assert.Equal(t, TOML, Default("PUT", MIMETOML)) assert.Equal(t, TOML, Default("PUT", MIMETOML))

View File

@ -1060,7 +1060,7 @@ func TestContextRenderUTF8Attachment(t *testing.T) {
} }
// TestContextRenderYAML tests that the response is serialized as YAML // TestContextRenderYAML tests that the response is serialized as YAML
// and Content-Type is set to application/x-yaml // and Content-Type is set to application/yaml
func TestContextRenderYAML(t *testing.T) { func TestContextRenderYAML(t *testing.T) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
c, _ := CreateTestContext(w) c, _ := CreateTestContext(w)
@ -1069,7 +1069,7 @@ func TestContextRenderYAML(t *testing.T) {
assert.Equal(t, http.StatusCreated, w.Code) assert.Equal(t, http.StatusCreated, w.Code)
assert.Equal(t, "foo: bar\n", w.Body.String()) assert.Equal(t, "foo: bar\n", w.Body.String())
assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type")) assert.Equal(t, "application/yaml; charset=utf-8", w.Header().Get("Content-Type"))
} }
// TestContextRenderTOML tests that the response is serialized as TOML // TestContextRenderTOML tests that the response is serialized as TOML
@ -1217,7 +1217,7 @@ func TestContextNegotiationWithYAML(t *testing.T) {
assert.Equal(t, http.StatusOK, w.Code) assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "foo: bar\n", w.Body.String()) assert.Equal(t, "foo: bar\n", w.Body.String())
assert.Equal(t, "application/x-yaml; charset=utf-8", w.Header().Get("Content-Type")) assert.Equal(t, "application/yaml; charset=utf-8", w.Header().Get("Content-Type"))
} }
func TestContextNegotiationWithTOML(t *testing.T) { func TestContextNegotiationWithTOML(t *testing.T) {

View File

@ -280,12 +280,12 @@ b:
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/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, "|4-\n a : Easy!\n b:\n \tc: 2\n \td: [3, 4]\n \t\n", w.Body.String()) assert.Equal(t, "|4-\n a : Easy!\n b:\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/yaml; charset=utf-8", w.Header().Get("Content-Type"))
} }
type fail struct{} type fail struct{}

View File

@ -15,7 +15,7 @@ type YAML struct {
Data any Data any
} }
var yamlContentType = []string{"application/x-yaml; charset=utf-8"} var yamlContentType = []string{"application/yaml; charset=utf-8"}
// Render (YAML) marshals the given interface object and writes data with custom ContentType. // Render (YAML) marshals the given interface object and writes data with custom ContentType.
func (r YAML) Render(w http.ResponseWriter) error { func (r YAML) Render(w http.ResponseWriter) error {