Repository: getkin/kin-openapi
Pull request #953 (2024-06-01 12:39:54)

openapi3filter: add context to Validator Middleware's ErrFunc and LogFunc functions
This feature modifies the ErrFunc and LogFunc of the validator, just as described in #472 
In contrast to the change described in the issue, this is not a breaking changes, since it adds additional functions to set the LogFunc and the ErrFunc instead of overwriting the existing ones.


Patch:
diff --git a/.github/docs/openapi3.txt b/.github/docs/openapi3.txt
index 993d2da..ef878a0 100644
--- a/.github/docs/openapi3.txt
+++ b/.github/docs/openapi3.txt
@@ -170,6 +170,9 @@ func (callback *Callback) Map() (m map[string]*PathItem)
 func (callback *Callback) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Callback.
 
+func (callback *Callback) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Callback.
+
 func (callback *Callback) Set(key string, value *PathItem)
     Set adds or replaces key 'key' of 'callback' with 'value'. Note: 'callback'
     MUST be non-nil
@@ -235,6 +238,9 @@ func NewComponents() Components
 func (components Components) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Components.
 
+func (components Components) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Components.
+
 func (components *Components) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets Components to a copy of data.
 
@@ -255,6 +261,9 @@ type Contact struct {
 func (contact Contact) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Contact.
 
+func (contact Contact) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Contact.
+
 func (contact *Contact) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets Contact to a copy of data.
 
@@ -295,6 +304,9 @@ type Discriminator struct {
 func (discriminator Discriminator) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Discriminator.
 
+func (discriminator Discriminator) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Discriminator.
+
 func (discriminator *Discriminator) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets Discriminator to a copy of data.
 
@@ -319,6 +331,9 @@ func NewEncoding() *Encoding
 func (encoding Encoding) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Encoding.
 
+func (encoding Encoding) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Encoding.
+
 func (encoding *Encoding) SerializationMethod() *SerializationMethod
     SerializationMethod returns a serialization method of request body.
     When serialization method is not defined the method returns the default
@@ -350,6 +365,9 @@ func NewExample(value interface{}) *Example
 func (example Example) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Example.
 
+func (example Example) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Example.
+
 func (example *Example) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets Example to a copy of data.
 
@@ -399,6 +417,9 @@ type ExternalDocs struct {
 func (e ExternalDocs) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of ExternalDocs.
 
+func (e ExternalDocs) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of ExternalDocs.
+
 func (e *ExternalDocs) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets ExternalDocs to a copy of data.
 
@@ -487,6 +508,9 @@ type Info struct {
 func (info Info) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Info.
 
+func (info Info) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Info.
+
 func (info *Info) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets Info to a copy of data.
 
@@ -505,6 +529,9 @@ type License struct {
 func (license License) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of License.
 
+func (license License) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of License.
+
 func (license *License) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets License to a copy of data.
 
@@ -527,6 +554,9 @@ type Link struct {
 func (link Link) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Link.
 
+func (link Link) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Link.
+
 func (link *Link) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets Link to a copy of data.
 
@@ -622,6 +652,9 @@ func (mediaType MediaType) JSONLookup(token string) (interface{}, error)
 func (mediaType MediaType) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of MediaType.
 
+func (mediaType MediaType) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of MediaType.
+
 func (mediaType *MediaType) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets MediaType to a copy of data.
 
@@ -687,6 +720,9 @@ type OAuthFlow struct {
 func (flow OAuthFlow) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of OAuthFlow.
 
+func (flow OAuthFlow) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of OAuthFlow.
+
 func (flow *OAuthFlow) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets OAuthFlow to a copy of data.
 
@@ -708,6 +744,9 @@ type OAuthFlows struct {
 func (flows OAuthFlows) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of OAuthFlows.
 
+func (flows OAuthFlows) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of OAuthFlows.
+
 func (flows *OAuthFlows) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets OAuthFlows to a copy of data.
 
@@ -769,6 +808,9 @@ func (operation Operation) JSONLookup(token string) (interface{}, error)
 func (operation Operation) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Operation.
 
+func (operation Operation) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Operation.
+
 func (operation *Operation) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets Operation to a copy of data.
 
@@ -811,6 +853,9 @@ func (parameter Parameter) JSONLookup(token string) (interface{}, error)
 func (parameter Parameter) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Parameter.
 
+func (parameter Parameter) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Parameter.
+
 func (parameter *Parameter) SerializationMethod() (*SerializationMethod, error)
     SerializationMethod returns a parameter's serialization method. When a
     parameter's serialization method is not defined the method returns the
@@ -901,6 +946,9 @@ func (pathItem *PathItem) GetOperation(method string) *Operation
 func (pathItem PathItem) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of PathItem.
 
+func (pathItem PathItem) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of PathItem.
+
 func (pathItem *PathItem) Operations() map[string]*Operation
 
 func (pathItem *PathItem) SetOperation(method string, operation *Operation)
@@ -963,8 +1011,8 @@ func (paths *Paths) Map() (m map[string]*PathItem)
 func (paths *Paths) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Paths.
 
-func (paths *Paths) MarshalYAML() (any, error)
-    Support YAML Marshaler interface for gopkg.in/yaml
+func (paths *Paths) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Paths.
 
 func (paths *Paths) Set(key string, value *PathItem)
     Set adds or replaces key 'key' of 'paths' with 'value'. Note: 'paths' MUST
@@ -1031,6 +1079,9 @@ func (requestBody *RequestBody) GetMediaType(mediaType string) *MediaType
 func (requestBody RequestBody) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of RequestBody.
 
+func (requestBody RequestBody) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of RequestBody.
+
 func (requestBody *RequestBody) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets RequestBody to a copy of data.
 
@@ -1097,6 +1148,9 @@ func NewResponse() *Response
 func (response Response) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Response.
 
+func (response Response) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Response.
+
 func (response *Response) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets Response to a copy of data.
 
@@ -1177,8 +1231,8 @@ func (responses *Responses) Map() (m map[string]*ResponseRef)
 func (responses *Responses) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Responses.
 
-func (responses *Responses) MarshalYAML() (any, error)
-    Support YAML Marshaler interface for gopkg.in/yaml
+func (responses *Responses) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Responses.
 
 func (responses *Responses) Set(key string, value *ResponseRef)
     Set adds or replaces key 'key' of 'responses' with 'value'. Note:
@@ -1307,6 +1361,9 @@ func (schema Schema) JSONLookup(token string) (interface{}, error)
 func (schema Schema) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Schema.
 
+func (schema Schema) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Schema.
+
 func (schema *Schema) NewRef() *SchemaRef
 
 func (schema *Schema) PermitsNull() bool
@@ -1536,6 +1593,9 @@ func NewSecurityScheme() *SecurityScheme
 func (ss SecurityScheme) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of SecurityScheme.
 
+func (ss SecurityScheme) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of SecurityScheme.
+
 func (ss *SecurityScheme) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets SecurityScheme to a copy of data.
 
@@ -1611,6 +1671,9 @@ func (server *Server) BasePath() (string, error)
 func (server Server) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Server.
 
+func (server Server) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Server.
+
 func (server Server) MatchRawURL(input string) ([]string, string, bool)
 
 func (server Server) ParameterNames() ([]string, error)
@@ -1634,6 +1697,9 @@ type ServerVariable struct {
 func (serverVariable ServerVariable) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of ServerVariable.
 
+func (serverVariable ServerVariable) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of ServerVariable.
+
 func (serverVariable *ServerVariable) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets ServerVariable to a copy of data.
 
@@ -1699,6 +1765,9 @@ func (doc *T) JSONLookup(token string) (interface{}, error)
 func (doc *T) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of T.
 
+func (doc *T) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of T.
+
 func (doc *T) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets T to a copy of data.
 
@@ -1719,6 +1788,9 @@ type Tag struct {
 func (t Tag) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of Tag.
 
+func (t Tag) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of Tag.
+
 func (t *Tag) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets Tag to a copy of data.
 
@@ -1813,6 +1885,9 @@ type XML struct {
 func (xml XML) MarshalJSON() ([]byte, error)
     MarshalJSON returns the JSON encoding of XML.
 
+func (xml XML) MarshalYAML() (interface{}, error)
+    MarshalYAML returns the YAML encoding of XML.
+
 func (xml *XML) UnmarshalJSON(data []byte) error
     UnmarshalJSON sets XML to a copy of data.
 
diff --git a/.github/docs/openapi3filter.txt b/.github/docs/openapi3filter.txt
index 0fd7027..43540c4 100644
--- a/.github/docs/openapi3filter.txt
+++ b/.github/docs/openapi3filter.txt
@@ -182,7 +182,7 @@ type ErrCode int
     occur during validation. These may be used to write an appropriate response
     in ErrFunc.
 
-type ErrFunc func(w http.ResponseWriter, status int, code ErrCode, err error)
+type ErrFunc func(ctx context.Context, w http.ResponseWriter, status int, code ErrCode, err error)
     ErrFunc handles errors that may occur during validation.
 
 type ErrorEncoder func(ctx context.Context, err error, w http.ResponseWriter)
@@ -198,7 +198,7 @@ type Headerer interface {
     Headerer, the provided headers will be applied to the response writer,
     after the Content-Type is set.
 
-type LogFunc func(message string, err error)
+type LogFunc func(ctx context.Context, message string, err error)
     LogFunc handles log messages that may occur during validation.
 
 type Options struct {
diff --git a/maps.sh b/maps.sh
index 0f7e14c..7e335b0 100755
--- a/maps.sh
+++ b/maps.sh
@@ -156,8 +156,8 @@ EOF
 
 maplike_UnMarsh() {
 	cat <<EOF >>"$maplike"
-// MarshalJSON returns the JSON encoding of ${type#'*'}.
-func (${name} ${type}) MarshalJSON() ([]byte, error) {
+// MarshalYAML returns the YAML encoding of ${type#'*'}.
+func (${name} ${type}) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, ${name}.Len()+len(${name}.Extensions))
 	for k, v := range ${name}.Extensions {
 		m[k] = v
@@ -165,7 +165,16 @@ func (${name} ${type}) MarshalJSON() ([]byte, error) {
 	for k, v := range ${name}.Map() {
 		m[k] = v
 	}
-	return json.Marshal(m)
+	return m, nil
+}
+
+// MarshalJSON returns the JSON encoding of ${type#'*'}.
+func (${name} ${type}) MarshalJSON() ([]byte, error) {
+	${name}Yaml, err := ${name}.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(${name}Yaml)
 }
 
 // UnmarshalJSON sets ${type#'*'} to a copy of data.
diff --git a/openapi2/marsh.go b/openapi2/marsh.go
index b15f3b8..5aa162a 100644
--- a/openapi2/marsh.go
+++ b/openapi2/marsh.go
@@ -17,10 +17,18 @@ func unmarshalError(jsonUnmarshalErr error) error {
 }
 
 func unmarshal(data []byte, v interface{}) error {
+	var jsonErr, yamlErr error
+
 	// See https://github.com/getkin/kin-openapi/issues/680
-	if err := json.Unmarshal(data, v); err != nil {
-		// UnmarshalStrict(data, v) TODO: investigate how ymlv3 handles duplicate map keys
-		return yaml.Unmarshal(data, v)
+	if jsonErr = json.Unmarshal(data, v); jsonErr == nil {
+		return nil
+	}
+
+	// UnmarshalStrict(data, v) TODO: investigate how ymlv3 handles duplicate map keys
+	if yamlErr = yaml.Unmarshal(data, v); yamlErr == nil {
+		return nil
 	}
-	return nil
+
+	// If both unmarshaling attempts fail, return a new error that includes both errors
+	return fmt.Errorf("failed to unmarshal data: json error: %v, yaml error: %v", jsonErr, yamlErr)
 }
diff --git a/openapi3/components.go b/openapi3/components.go
index 656ea19..c466632 100644
--- a/openapi3/components.go
+++ b/openapi3/components.go
@@ -43,6 +43,15 @@ func NewComponents() Components {
 
 // MarshalJSON returns the JSON encoding of Components.
 func (components Components) MarshalJSON() ([]byte, error) {
+	x, err := components.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Components.
+func (components Components) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 9+len(components.Extensions))
 	for k, v := range components.Extensions {
 		m[k] = v
@@ -74,7 +83,7 @@ func (components Components) MarshalJSON() ([]byte, error) {
 	if x := components.Callbacks; len(x) != 0 {
 		m["callbacks"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Components to a copy of data.
diff --git a/openapi3/contact.go b/openapi3/contact.go
index e60d281..7b707ce 100644
--- a/openapi3/contact.go
+++ b/openapi3/contact.go
@@ -17,6 +17,15 @@ type Contact struct {
 
 // MarshalJSON returns the JSON encoding of Contact.
 func (contact Contact) MarshalJSON() ([]byte, error) {
+	x, err := contact.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Contact.
+func (contact Contact) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 3+len(contact.Extensions))
 	for k, v := range contact.Extensions {
 		m[k] = v
@@ -30,7 +39,7 @@ func (contact Contact) MarshalJSON() ([]byte, error) {
 	if x := contact.Email; x != "" {
 		m["email"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Contact to a copy of data.
diff --git a/openapi3/discriminator.go b/openapi3/discriminator.go
index abb4807..ae36f41 100644
--- a/openapi3/discriminator.go
+++ b/openapi3/discriminator.go
@@ -16,6 +16,15 @@ type Discriminator struct {
 
 // MarshalJSON returns the JSON encoding of Discriminator.
 func (discriminator Discriminator) MarshalJSON() ([]byte, error) {
+	x, err := discriminator.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Discriminator.
+func (discriminator Discriminator) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 2+len(discriminator.Extensions))
 	for k, v := range discriminator.Extensions {
 		m[k] = v
@@ -24,7 +33,7 @@ func (discriminator Discriminator) MarshalJSON() ([]byte, error) {
 	if x := discriminator.Mapping; len(x) != 0 {
 		m["mapping"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Discriminator to a copy of data.
diff --git a/openapi3/encoding.go b/openapi3/encoding.go
index 8e81027..57d20ee 100644
--- a/openapi3/encoding.go
+++ b/openapi3/encoding.go
@@ -41,6 +41,15 @@ func (encoding *Encoding) WithHeaderRef(name string, ref *HeaderRef) *Encoding {
 
 // MarshalJSON returns the JSON encoding of Encoding.
 func (encoding Encoding) MarshalJSON() ([]byte, error) {
+	x, err := encoding.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Encoding.
+func (encoding Encoding) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 5+len(encoding.Extensions))
 	for k, v := range encoding.Extensions {
 		m[k] = v
@@ -60,7 +69,7 @@ func (encoding Encoding) MarshalJSON() ([]byte, error) {
 	if x := encoding.AllowReserved; x {
 		m["allowReserved"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Encoding to a copy of data.
diff --git a/openapi3/example.go b/openapi3/example.go
index 44e71d8..a1a5a2b 100644
--- a/openapi3/example.go
+++ b/openapi3/example.go
@@ -23,6 +23,15 @@ func NewExample(value interface{}) *Example {
 
 // MarshalJSON returns the JSON encoding of Example.
 func (example Example) MarshalJSON() ([]byte, error) {
+	x, err := example.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Example.
+func (example Example) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 4+len(example.Extensions))
 	for k, v := range example.Extensions {
 		m[k] = v
@@ -39,7 +48,7 @@ func (example Example) MarshalJSON() ([]byte, error) {
 	if x := example.ExternalValue; x != "" {
 		m["externalValue"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Example to a copy of data.
diff --git a/openapi3/external_docs.go b/openapi3/external_docs.go
index 7190be4..40e9f3d 100644
--- a/openapi3/external_docs.go
+++ b/openapi3/external_docs.go
@@ -19,6 +19,15 @@ type ExternalDocs struct {
 
 // MarshalJSON returns the JSON encoding of ExternalDocs.
 func (e ExternalDocs) MarshalJSON() ([]byte, error) {
+	x, err := e.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of ExternalDocs.
+func (e ExternalDocs) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 2+len(e.Extensions))
 	for k, v := range e.Extensions {
 		m[k] = v
@@ -29,7 +38,7 @@ func (e ExternalDocs) MarshalJSON() ([]byte, error) {
 	if x := e.URL; x != "" {
 		m["url"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets ExternalDocs to a copy of data.
diff --git a/openapi3/info.go b/openapi3/info.go
index ffcd3b0..51707f8 100644
--- a/openapi3/info.go
+++ b/openapi3/info.go
@@ -21,6 +21,15 @@ type Info struct {
 
 // MarshalJSON returns the JSON encoding of Info.
 func (info Info) MarshalJSON() ([]byte, error) {
+	x, err := info.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Info.
+func (info Info) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 6+len(info.Extensions))
 	for k, v := range info.Extensions {
 		m[k] = v
@@ -39,7 +48,7 @@ func (info Info) MarshalJSON() ([]byte, error) {
 		m["license"] = x
 	}
 	m["version"] = info.Version
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Info to a copy of data.
diff --git a/openapi3/license.go b/openapi3/license.go
index 3d2d2f0..e845ed8 100644
--- a/openapi3/license.go
+++ b/openapi3/license.go
@@ -17,6 +17,15 @@ type License struct {
 
 // MarshalJSON returns the JSON encoding of License.
 func (license License) MarshalJSON() ([]byte, error) {
+	x, err := license.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of License.
+func (license License) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 2+len(license.Extensions))
 	for k, v := range license.Extensions {
 		m[k] = v
@@ -25,7 +34,7 @@ func (license License) MarshalJSON() ([]byte, error) {
 	if x := license.URL; x != "" {
 		m["url"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets License to a copy of data.
diff --git a/openapi3/link.go b/openapi3/link.go
index 23a8df4..9615665 100644
--- a/openapi3/link.go
+++ b/openapi3/link.go
@@ -22,6 +22,15 @@ type Link struct {
 
 // MarshalJSON returns the JSON encoding of Link.
 func (link Link) MarshalJSON() ([]byte, error) {
+	x, err := link.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Link.
+func (link Link) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 6+len(link.Extensions))
 	for k, v := range link.Extensions {
 		m[k] = v
@@ -46,7 +55,7 @@ func (link Link) MarshalJSON() ([]byte, error) {
 		m["requestBody"] = x
 	}
 
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Link to a copy of data.
diff --git a/openapi3/maplike.go b/openapi3/maplike.go
index b27cbf6..8829b8d 100644
--- a/openapi3/maplike.go
+++ b/openapi3/maplike.go
@@ -76,8 +76,8 @@ func (responses Responses) JSONLookup(token string) (interface{}, error) {
 	}
 }
 
-// MarshalJSON returns the JSON encoding of Responses.
-func (responses *Responses) MarshalJSON() ([]byte, error) {
+// MarshalYAML returns the YAML encoding of Responses.
+func (responses *Responses) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, responses.Len()+len(responses.Extensions))
 	for k, v := range responses.Extensions {
 		m[k] = v
@@ -85,7 +85,16 @@ func (responses *Responses) MarshalJSON() ([]byte, error) {
 	for k, v := range responses.Map() {
 		m[k] = v
 	}
-	return json.Marshal(m)
+	return m, nil
+}
+
+// MarshalJSON returns the JSON encoding of Responses.
+func (responses *Responses) MarshalJSON() ([]byte, error) {
+	responsesYaml, err := responses.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(responsesYaml)
 }
 
 // UnmarshalJSON sets Responses to a copy of data.
@@ -195,8 +204,8 @@ func (callback Callback) JSONLookup(token string) (interface{}, error) {
 	}
 }
 
-// MarshalJSON returns the JSON encoding of Callback.
-func (callback *Callback) MarshalJSON() ([]byte, error) {
+// MarshalYAML returns the YAML encoding of Callback.
+func (callback *Callback) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, callback.Len()+len(callback.Extensions))
 	for k, v := range callback.Extensions {
 		m[k] = v
@@ -204,7 +213,16 @@ func (callback *Callback) MarshalJSON() ([]byte, error) {
 	for k, v := range callback.Map() {
 		m[k] = v
 	}
-	return json.Marshal(m)
+	return m, nil
+}
+
+// MarshalJSON returns the JSON encoding of Callback.
+func (callback *Callback) MarshalJSON() ([]byte, error) {
+	callbackYaml, err := callback.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(callbackYaml)
 }
 
 // UnmarshalJSON sets Callback to a copy of data.
@@ -314,8 +332,8 @@ func (paths Paths) JSONLookup(token string) (interface{}, error) {
 	}
 }
 
-// MarshalJSON returns the JSON encoding of Paths.
-func (paths *Paths) MarshalJSON() ([]byte, error) {
+// MarshalYAML returns the YAML encoding of Paths.
+func (paths *Paths) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, paths.Len()+len(paths.Extensions))
 	for k, v := range paths.Extensions {
 		m[k] = v
@@ -323,7 +341,16 @@ func (paths *Paths) MarshalJSON() ([]byte, error) {
 	for k, v := range paths.Map() {
 		m[k] = v
 	}
-	return json.Marshal(m)
+	return m, nil
+}
+
+// MarshalJSON returns the JSON encoding of Paths.
+func (paths *Paths) MarshalJSON() ([]byte, error) {
+	pathsYaml, err := paths.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(pathsYaml)
 }
 
 // UnmarshalJSON sets Paths to a copy of data.
diff --git a/openapi3/marsh.go b/openapi3/marsh.go
index 18036ae..9be7bb4 100644
--- a/openapi3/marsh.go
+++ b/openapi3/marsh.go
@@ -17,10 +17,18 @@ func unmarshalError(jsonUnmarshalErr error) error {
 }
 
 func unmarshal(data []byte, v interface{}) error {
+	var jsonErr, yamlErr error
+
 	// See https://github.com/getkin/kin-openapi/issues/680
-	if err := json.Unmarshal(data, v); err != nil {
-		// UnmarshalStrict(data, v) TODO: investigate how ymlv3 handles duplicate map keys
-		return yaml.Unmarshal(data, v)
+	if jsonErr = json.Unmarshal(data, v); jsonErr == nil {
+		return nil
+	}
+
+	// UnmarshalStrict(data, v) TODO: investigate how ymlv3 handles duplicate map keys
+	if yamlErr = yaml.Unmarshal(data, v); yamlErr == nil {
+		return nil
 	}
-	return nil
+
+	// If both unmarshaling attempts fail, return a new error that includes both errors
+	return fmt.Errorf("failed to unmarshal data: json error: %v, yaml error: %v", jsonErr, yamlErr)
 }
diff --git a/openapi3/media_type.go b/openapi3/media_type.go
index e043a7c..02de1db 100644
--- a/openapi3/media_type.go
+++ b/openapi3/media_type.go
@@ -65,6 +65,15 @@ func (mediaType *MediaType) WithEncoding(name string, enc *Encoding) *MediaType
 
 // MarshalJSON returns the JSON encoding of MediaType.
 func (mediaType MediaType) MarshalJSON() ([]byte, error) {
+	x, err := mediaType.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of MediaType.
+func (mediaType MediaType) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 4+len(mediaType.Extensions))
 	for k, v := range mediaType.Extensions {
 		m[k] = v
@@ -81,7 +90,7 @@ func (mediaType MediaType) MarshalJSON() ([]byte, error) {
 	if x := mediaType.Encoding; len(x) != 0 {
 		m["encoding"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets MediaType to a copy of data.
diff --git a/openapi3/openapi3.go b/openapi3/openapi3.go
index 04df350..04bac8f 100644
--- a/openapi3/openapi3.go
+++ b/openapi3/openapi3.go
@@ -55,6 +55,15 @@ func (doc *T) JSONLookup(token string) (interface{}, error) {
 
 // MarshalJSON returns the JSON encoding of T.
 func (doc *T) MarshalJSON() ([]byte, error) {
+	x, err := doc.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of T.
+func (doc *T) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 4+len(doc.Extensions))
 	for k, v := range doc.Extensions {
 		m[k] = v
@@ -77,7 +86,7 @@ func (doc *T) MarshalJSON() ([]byte, error) {
 	if x := doc.ExternalDocs; x != nil {
 		m["externalDocs"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets T to a copy of data.
diff --git a/openapi3/operation.go b/openapi3/operation.go
index d859a43..41e3c9b 100644
--- a/openapi3/operation.go
+++ b/openapi3/operation.go
@@ -58,6 +58,15 @@ func NewOperation() *Operation {
 
 // MarshalJSON returns the JSON encoding of Operation.
 func (operation Operation) MarshalJSON() ([]byte, error) {
+	x, err := operation.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Operation.
+func (operation Operation) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 12+len(operation.Extensions))
 	for k, v := range operation.Extensions {
 		m[k] = v
@@ -96,7 +105,7 @@ func (operation Operation) MarshalJSON() ([]byte, error) {
 	if x := operation.ExternalDocs; x != nil {
 		m["externalDocs"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Operation to a copy of data.
diff --git a/openapi3/parameter.go b/openapi3/parameter.go
index f5a157d..a13c112 100644
--- a/openapi3/parameter.go
+++ b/openapi3/parameter.go
@@ -150,6 +150,15 @@ func (parameter *Parameter) WithSchema(value *Schema) *Parameter {
 
 // MarshalJSON returns the JSON encoding of Parameter.
 func (parameter Parameter) MarshalJSON() ([]byte, error) {
+	x, err := parameter.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Parameter.
+func (parameter Parameter) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 13+len(parameter.Extensions))
 	for k, v := range parameter.Extensions {
 		m[k] = v
@@ -195,7 +204,7 @@ func (parameter Parameter) MarshalJSON() ([]byte, error) {
 		m["content"] = x
 	}
 
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Parameter to a copy of data.
diff --git a/openapi3/path_item.go b/openapi3/path_item.go
index e5dd0fb..0a6493a 100644
--- a/openapi3/path_item.go
+++ b/openapi3/path_item.go
@@ -31,8 +31,17 @@ type PathItem struct {
 
 // MarshalJSON returns the JSON encoding of PathItem.
 func (pathItem PathItem) MarshalJSON() ([]byte, error) {
+	x, err := pathItem.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of PathItem.
+func (pathItem PathItem) MarshalYAML() (interface{}, error) {
 	if ref := pathItem.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+		return Ref{Ref: ref}, nil
 	}
 
 	m := make(map[string]interface{}, 13+len(pathItem.Extensions))
@@ -78,7 +87,7 @@ func (pathItem PathItem) MarshalJSON() ([]byte, error) {
 	if x := pathItem.Parameters; len(x) != 0 {
 		m["parameters"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets PathItem to a copy of data.
diff --git a/openapi3/paths.go b/openapi3/paths.go
index daafe71..ac4f58b 100644
--- a/openapi3/paths.go
+++ b/openapi3/paths.go
@@ -218,21 +218,6 @@ func (paths *Paths) validateUniqueOperationIDs() error {
 	return nil
 }
 
-// Support YAML Marshaler interface for gopkg.in/yaml
-func (paths *Paths) MarshalYAML() (any, error) {
-	res := make(map[string]any, len(paths.Extensions)+len(paths.m))
-
-	for k, v := range paths.Extensions {
-		res[k] = v
-	}
-
-	for k, v := range paths.m {
-		res[k] = v
-	}
-
-	return res, nil
-}
-
 func normalizeTemplatedPath(path string) (string, uint, map[string]struct{}) {
 	if strings.IndexByte(path, '{') < 0 {
 		return path, 0, nil
diff --git a/openapi3/refs.go b/openapi3/refs.go
index a7e1e36..99237f1 100644
--- a/openapi3/refs.go
+++ b/openapi3/refs.go
@@ -27,15 +27,16 @@ func (x CallbackRef) MarshalYAML() (interface{}, error) {
 	if ref := x.Ref; ref != "" {
 		return &Ref{Ref: ref}, nil
 	}
-	return x.Value, nil
+	return x.Value.MarshalYAML()
 }
 
 // MarshalJSON returns the JSON encoding of CallbackRef.
 func (x CallbackRef) MarshalJSON() ([]byte, error) {
-	if ref := x.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+	y, err := x.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
-	return json.Marshal(x.Value)
+	return json.Marshal(y)
 }
 
 // UnmarshalJSON sets CallbackRef to a copy of data.
@@ -105,15 +106,16 @@ func (x ExampleRef) MarshalYAML() (interface{}, error) {
 	if ref := x.Ref; ref != "" {
 		return &Ref{Ref: ref}, nil
 	}
-	return x.Value, nil
+	return x.Value.MarshalYAML()
 }
 
 // MarshalJSON returns the JSON encoding of ExampleRef.
 func (x ExampleRef) MarshalJSON() ([]byte, error) {
-	if ref := x.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+	y, err := x.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
-	return x.Value.MarshalJSON()
+	return json.Marshal(y)
 }
 
 // UnmarshalJSON sets ExampleRef to a copy of data.
@@ -183,15 +185,16 @@ func (x HeaderRef) MarshalYAML() (interface{}, error) {
 	if ref := x.Ref; ref != "" {
 		return &Ref{Ref: ref}, nil
 	}
-	return x.Value, nil
+	return x.Value.MarshalYAML()
 }
 
 // MarshalJSON returns the JSON encoding of HeaderRef.
 func (x HeaderRef) MarshalJSON() ([]byte, error) {
-	if ref := x.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+	y, err := x.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
-	return x.Value.MarshalJSON()
+	return json.Marshal(y)
 }
 
 // UnmarshalJSON sets HeaderRef to a copy of data.
@@ -261,15 +264,16 @@ func (x LinkRef) MarshalYAML() (interface{}, error) {
 	if ref := x.Ref; ref != "" {
 		return &Ref{Ref: ref}, nil
 	}
-	return x.Value, nil
+	return x.Value.MarshalYAML()
 }
 
 // MarshalJSON returns the JSON encoding of LinkRef.
 func (x LinkRef) MarshalJSON() ([]byte, error) {
-	if ref := x.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+	y, err := x.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
-	return x.Value.MarshalJSON()
+	return json.Marshal(y)
 }
 
 // UnmarshalJSON sets LinkRef to a copy of data.
@@ -339,15 +343,16 @@ func (x ParameterRef) MarshalYAML() (interface{}, error) {
 	if ref := x.Ref; ref != "" {
 		return &Ref{Ref: ref}, nil
 	}
-	return x.Value, nil
+	return x.Value.MarshalYAML()
 }
 
 // MarshalJSON returns the JSON encoding of ParameterRef.
 func (x ParameterRef) MarshalJSON() ([]byte, error) {
-	if ref := x.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+	y, err := x.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
-	return x.Value.MarshalJSON()
+	return json.Marshal(y)
 }
 
 // UnmarshalJSON sets ParameterRef to a copy of data.
@@ -417,15 +422,16 @@ func (x RequestBodyRef) MarshalYAML() (interface{}, error) {
 	if ref := x.Ref; ref != "" {
 		return &Ref{Ref: ref}, nil
 	}
-	return x.Value, nil
+	return x.Value.MarshalYAML()
 }
 
 // MarshalJSON returns the JSON encoding of RequestBodyRef.
 func (x RequestBodyRef) MarshalJSON() ([]byte, error) {
-	if ref := x.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+	y, err := x.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
-	return x.Value.MarshalJSON()
+	return json.Marshal(y)
 }
 
 // UnmarshalJSON sets RequestBodyRef to a copy of data.
@@ -495,15 +501,16 @@ func (x ResponseRef) MarshalYAML() (interface{}, error) {
 	if ref := x.Ref; ref != "" {
 		return &Ref{Ref: ref}, nil
 	}
-	return x.Value, nil
+	return x.Value.MarshalYAML()
 }
 
 // MarshalJSON returns the JSON encoding of ResponseRef.
 func (x ResponseRef) MarshalJSON() ([]byte, error) {
-	if ref := x.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+	y, err := x.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
-	return x.Value.MarshalJSON()
+	return json.Marshal(y)
 }
 
 // UnmarshalJSON sets ResponseRef to a copy of data.
@@ -573,15 +580,16 @@ func (x SchemaRef) MarshalYAML() (interface{}, error) {
 	if ref := x.Ref; ref != "" {
 		return &Ref{Ref: ref}, nil
 	}
-	return x.Value, nil
+	return x.Value.MarshalYAML()
 }
 
 // MarshalJSON returns the JSON encoding of SchemaRef.
 func (x SchemaRef) MarshalJSON() ([]byte, error) {
-	if ref := x.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+	y, err := x.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
-	return x.Value.MarshalJSON()
+	return json.Marshal(y)
 }
 
 // UnmarshalJSON sets SchemaRef to a copy of data.
@@ -651,15 +659,16 @@ func (x SecuritySchemeRef) MarshalYAML() (interface{}, error) {
 	if ref := x.Ref; ref != "" {
 		return &Ref{Ref: ref}, nil
 	}
-	return x.Value, nil
+	return x.Value.MarshalYAML()
 }
 
 // MarshalJSON returns the JSON encoding of SecuritySchemeRef.
 func (x SecuritySchemeRef) MarshalJSON() ([]byte, error) {
-	if ref := x.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+	y, err := x.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
-	return x.Value.MarshalJSON()
+	return json.Marshal(y)
 }
 
 // UnmarshalJSON sets SecuritySchemeRef to a copy of data.
diff --git a/openapi3/request_body.go b/openapi3/request_body.go
index acd2d0e..7b8d353 100644
--- a/openapi3/request_body.go
+++ b/openapi3/request_body.go
@@ -75,6 +75,15 @@ func (requestBody *RequestBody) GetMediaType(mediaType string) *MediaType {
 
 // MarshalJSON returns the JSON encoding of RequestBody.
 func (requestBody RequestBody) MarshalJSON() ([]byte, error) {
+	x, err := requestBody.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of RequestBody.
+func (requestBody RequestBody) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 3+len(requestBody.Extensions))
 	for k, v := range requestBody.Extensions {
 		m[k] = v
@@ -88,7 +97,7 @@ func (requestBody RequestBody) MarshalJSON() ([]byte, error) {
 	if x := requestBody.Content; true {
 		m["content"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets RequestBody to a copy of data.
diff --git a/openapi3/response.go b/openapi3/response.go
index f69c237..6209b58 100644
--- a/openapi3/response.go
+++ b/openapi3/response.go
@@ -98,21 +98,6 @@ func (responses *Responses) Validate(ctx context.Context, opts ...ValidationOpti
 	return validateExtensions(ctx, responses.Extensions)
 }
 
-// Support YAML Marshaler interface for gopkg.in/yaml
-func (responses *Responses) MarshalYAML() (any, error) {
-	res := make(map[string]any, len(responses.Extensions)+len(responses.m))
-
-	for k, v := range responses.Extensions {
-		res[k] = v
-	}
-
-	for k, v := range responses.m {
-		res[k] = v
-	}
-
-	return res, nil
-}
-
 // Response is specified by OpenAPI/Swagger 3.0 standard.
 // See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#response-object
 type Response struct {
@@ -150,6 +135,15 @@ func (response *Response) WithJSONSchemaRef(schema *SchemaRef) *Response {
 
 // MarshalJSON returns the JSON encoding of Response.
 func (response Response) MarshalJSON() ([]byte, error) {
+	x, err := response.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Response.
+func (response Response) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 4+len(response.Extensions))
 	for k, v := range response.Extensions {
 		m[k] = v
@@ -166,7 +160,7 @@ func (response Response) MarshalJSON() ([]byte, error) {
 	if x := response.Links; len(x) != 0 {
 		m["links"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Response to a copy of data.
diff --git a/openapi3/schema.go b/openapi3/schema.go
index beac7ba..8bacf72 100644
--- a/openapi3/schema.go
+++ b/openapi3/schema.go
@@ -222,23 +222,18 @@ func (addProps AdditionalProperties) MarshalYAML() (interface{}, error) {
 		return false, nil
 	}
 	if x := addProps.Schema; x != nil {
-		return x.Value, nil
+		return x.MarshalYAML()
 	}
 	return nil, nil
 }
 
 // MarshalJSON returns the JSON encoding of AdditionalProperties.
 func (addProps AdditionalProperties) MarshalJSON() ([]byte, error) {
-	if x := addProps.Has; x != nil {
-		if *x {
-			return []byte("true"), nil
-		}
-		return []byte("false"), nil
-	}
-	if x := addProps.Schema; x != nil {
-		return json.Marshal(x)
+	x, err := addProps.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
-	return nil, nil
+	return json.Marshal(x)
 }
 
 // UnmarshalJSON sets AdditionalProperties to a copy of data.
@@ -275,6 +270,16 @@ func NewSchema() *Schema {
 
 // MarshalJSON returns the JSON encoding of Schema.
 func (schema Schema) MarshalJSON() ([]byte, error) {
+	m, err := schema.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+
+	return json.Marshal(m)
+}
+
+// MarshalYAML returns the YAML encoding of Schema.
+func (schema Schema) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 36+len(schema.Extensions))
 	for k, v := range schema.Extensions {
 		m[k] = v
@@ -401,7 +406,7 @@ func (schema Schema) MarshalJSON() ([]byte, error) {
 		m["discriminator"] = x
 	}
 
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Schema to a copy of data.
diff --git a/openapi3/security_scheme.go b/openapi3/security_scheme.go
index c07bfb6..7b6662c 100644
--- a/openapi3/security_scheme.go
+++ b/openapi3/security_scheme.go
@@ -52,6 +52,15 @@ func NewJWTSecurityScheme() *SecurityScheme {
 
 // MarshalJSON returns the JSON encoding of SecurityScheme.
 func (ss SecurityScheme) MarshalJSON() ([]byte, error) {
+	x, err := ss.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of SecurityScheme.
+func (ss SecurityScheme) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 8+len(ss.Extensions))
 	for k, v := range ss.Extensions {
 		m[k] = v
@@ -80,7 +89,7 @@ func (ss SecurityScheme) MarshalJSON() ([]byte, error) {
 	if x := ss.OpenIdConnectUrl; x != "" {
 		m["openIdConnectUrl"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets SecurityScheme to a copy of data.
@@ -225,6 +234,15 @@ const (
 
 // MarshalJSON returns the JSON encoding of OAuthFlows.
 func (flows OAuthFlows) MarshalJSON() ([]byte, error) {
+	x, err := flows.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of OAuthFlows.
+func (flows OAuthFlows) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 4+len(flows.Extensions))
 	for k, v := range flows.Extensions {
 		m[k] = v
@@ -241,7 +259,7 @@ func (flows OAuthFlows) MarshalJSON() ([]byte, error) {
 	if x := flows.AuthorizationCode; x != nil {
 		m["authorizationCode"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets OAuthFlows to a copy of data.
@@ -307,6 +325,15 @@ type OAuthFlow struct {
 
 // MarshalJSON returns the JSON encoding of OAuthFlow.
 func (flow OAuthFlow) MarshalJSON() ([]byte, error) {
+	x, err := flow.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of OAuthFlow.
+func (flow OAuthFlow) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 4+len(flow.Extensions))
 	for k, v := range flow.Extensions {
 		m[k] = v
@@ -321,7 +348,7 @@ func (flow OAuthFlow) MarshalJSON() ([]byte, error) {
 		m["refreshUrl"] = x
 	}
 	m["scopes"] = flow.Scopes
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets OAuthFlow to a copy of data.
diff --git a/openapi3/server.go b/openapi3/server.go
index 04e233d..85b716f 100644
--- a/openapi3/server.go
+++ b/openapi3/server.go
@@ -84,6 +84,15 @@ func (server *Server) BasePath() (string, error) {
 
 // MarshalJSON returns the JSON encoding of Server.
 func (server Server) MarshalJSON() ([]byte, error) {
+	x, err := server.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Server.
+func (server Server) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 3+len(server.Extensions))
 	for k, v := range server.Extensions {
 		m[k] = v
@@ -95,7 +104,7 @@ func (server Server) MarshalJSON() ([]byte, error) {
 	if x := server.Variables; len(x) != 0 {
 		m["variables"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Server to a copy of data.
@@ -234,6 +243,15 @@ type ServerVariable struct {
 
 // MarshalJSON returns the JSON encoding of ServerVariable.
 func (serverVariable ServerVariable) MarshalJSON() ([]byte, error) {
+	x, err := serverVariable.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of ServerVariable.
+func (serverVariable ServerVariable) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 4+len(serverVariable.Extensions))
 	for k, v := range serverVariable.Extensions {
 		m[k] = v
@@ -247,7 +265,7 @@ func (serverVariable ServerVariable) MarshalJSON() ([]byte, error) {
 	if x := serverVariable.Description; x != "" {
 		m["description"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets ServerVariable to a copy of data.
diff --git a/openapi3/tag.go b/openapi3/tag.go
index eea6462..8dc9967 100644
--- a/openapi3/tag.go
+++ b/openapi3/tag.go
@@ -42,6 +42,15 @@ type Tag struct {
 
 // MarshalJSON returns the JSON encoding of Tag.
 func (t Tag) MarshalJSON() ([]byte, error) {
+	x, err := t.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of Tag.
+func (t Tag) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 3+len(t.Extensions))
 	for k, v := range t.Extensions {
 		m[k] = v
@@ -55,7 +64,7 @@ func (t Tag) MarshalJSON() ([]byte, error) {
 	if x := t.ExternalDocs; x != nil {
 		m["externalDocs"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets Tag to a copy of data.
diff --git a/openapi3/xml.go b/openapi3/xml.go
index 604b607..e69c1fa 100644
--- a/openapi3/xml.go
+++ b/openapi3/xml.go
@@ -19,6 +19,15 @@ type XML struct {
 
 // MarshalJSON returns the JSON encoding of XML.
 func (xml XML) MarshalJSON() ([]byte, error) {
+	x, err := xml.MarshalYAML()
+	if err != nil {
+		return nil, err
+	}
+	return json.Marshal(x)
+}
+
+// MarshalYAML returns the YAML encoding of XML.
+func (xml XML) MarshalYAML() (interface{}, error) {
 	m := make(map[string]interface{}, 5+len(xml.Extensions))
 	for k, v := range xml.Extensions {
 		m[k] = v
@@ -38,7 +47,7 @@ func (xml XML) MarshalJSON() ([]byte, error) {
 	if x := xml.Wrapped; x {
 		m["wrapped"] = x
 	}
-	return json.Marshal(m)
+	return m, nil
 }
 
 // UnmarshalJSON sets XML to a copy of data.
diff --git a/openapi3filter/middleware.go b/openapi3filter/middleware.go
index 0009d61..d20889e 100644
--- a/openapi3filter/middleware.go
+++ b/openapi3filter/middleware.go
@@ -2,6 +2,7 @@ package openapi3filter
 
 import (
 	"bytes"
+	"context"
 	"io"
 	"log"
 	"net/http"
@@ -19,10 +20,10 @@ type Validator struct {
 }
 
 // ErrFunc handles errors that may occur during validation.
-type ErrFunc func(w http.ResponseWriter, status int, code ErrCode, err error)
+type ErrFunc func(ctx context.Context, w http.ResponseWriter, status int, code ErrCode, err error)
 
 // LogFunc handles log messages that may occur during validation.
-type LogFunc func(message string, err error)
+type LogFunc func(ctx context.Context, message string, err error)
 
 // ErrCode is used for classification of different types of errors that may
 // occur during validation. These may be used to write an appropriate response
@@ -61,10 +62,10 @@ func (e ErrCode) responseText() string {
 func NewValidator(router routers.Router, options ...ValidatorOption) *Validator {
 	v := &Validator{
 		router: router,
-		errFunc: func(w http.ResponseWriter, status int, code ErrCode, _ error) {
+		errFunc: func(_ context.Context, w http.ResponseWriter, status int, code ErrCode, _ error) {
 			http.Error(w, code.responseText(), status)
 		},
-		logFunc: func(message string, err error) {
+		logFunc: func(_ context.Context, message string, err error) {
 			log.Printf("%s: %v", message, err)
 		},
 	}
@@ -117,10 +118,11 @@ func ValidationOptions(options Options) ValidatorOption {
 // request and response validation.
 func (v *Validator) Middleware(h http.Handler) http.Handler {
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		ctx := r.Context()
 		route, pathParams, err := v.router.FindRoute(r)
 		if err != nil {
-			v.logFunc("validation error: failed to find route for "+r.URL.String(), err)
-			v.errFunc(w, http.StatusNotFound, ErrCodeCannotFindRoute, err)
+			v.logFunc(ctx, "validation error: failed to find route for "+r.URL.String(), err)
+			v.errFunc(ctx, w, http.StatusNotFound, ErrCodeCannotFindRoute, err)
 			return
 		}
 		requestValidationInput := &RequestValidationInput{
@@ -129,9 +131,9 @@ func (v *Validator) Middleware(h http.Handler) http.Handler {
 			Route:      route,
 			Options:    &v.options,
 		}
-		if err = ValidateRequest(r.Context(), requestValidationInput); err != nil {
-			v.logFunc("invalid request", err)
-			v.errFunc(w, http.StatusBadRequest, ErrCodeRequestInvalid, err)
+		if err = ValidateRequest(ctx, requestValidationInput); err != nil {
+			v.logFunc(ctx, "invalid request", err)
+			v.errFunc(ctx, w, http.StatusBadRequest, ErrCodeRequestInvalid, err)
 			return
 		}
 
@@ -144,22 +146,22 @@ func (v *Validator) Middleware(h http.Handler) http.Handler {
 
 		h.ServeHTTP(wr, r)
 
-		if err = ValidateResponse(r.Context(), &ResponseValidationInput{
+		if err = ValidateResponse(ctx, &ResponseValidationInput{
 			RequestValidationInput: requestValidationInput,
 			Status:                 wr.statusCode(),
 			Header:                 wr.Header(),
 			Body:                   io.NopCloser(bytes.NewBuffer(wr.bodyContents())),
 			Options:                &v.options,
 		}); err != nil {
-			v.logFunc("invalid response", err)
+			v.logFunc(ctx, "invalid response", err)
 			if v.strict {
-				v.errFunc(w, http.StatusInternalServerError, ErrCodeResponseInvalid, err)
+				v.errFunc(ctx, w, http.StatusInternalServerError, ErrCodeResponseInvalid, err)
 			}
 			return
 		}
 
 		if err = wr.flushBodyContents(); err != nil {
-			v.logFunc("failed to write response", err)
+			v.logFunc(ctx, "failed to write response", err)
 		}
 	})
 }
diff --git a/refs.sh b/refs.sh
index 9ece26e..a28ef3f 100755
--- a/refs.sh
+++ b/refs.sh
@@ -46,29 +46,17 @@ func (x ${type}Ref) MarshalYAML() (interface{}, error) {
 	if ref := x.Ref; ref != "" {
 		return &Ref{Ref: ref}, nil
 	}
-	return x.Value, nil
+	return x.Value.MarshalYAML()
 }
 
 // MarshalJSON returns the JSON encoding of ${type}Ref.
 func (x ${type}Ref) MarshalJSON() ([]byte, error) {
-	if ref := x.Ref; ref != "" {
-		return json.Marshal(Ref{Ref: ref})
+	y, err := x.MarshalYAML()
+	if err != nil {
+		return nil, err
 	}
+	return json.Marshal(y)
 EOF
-
-	case $type in
-		# Callback) echo '	return x.Value.MarshalJSON()' ;; TODO: when https://github.com/getkin/kin-openapi/issues/687
-		Example) echo '	return x.Value.MarshalJSON()' ;;
-		Header) echo '	return x.Value.MarshalJSON()' ;;
-		Link) echo '	return x.Value.MarshalJSON()' ;;
-		Parameter) echo '	return x.Value.MarshalJSON()' ;;
-		RequestBody) echo '	return x.Value.MarshalJSON()' ;;
-		Response) echo '	return x.Value.MarshalJSON()' ;;
-		Schema) echo '	return x.Value.MarshalJSON()' ;;
-		SecurityScheme) echo '	return x.Value.MarshalJSON()' ;;
-		*) echo '	return json.Marshal(x.Value)'
-	esac
-
 	cat <<EOF
 }
 


Test patch:
diff --git a/openapi3/openapi3_test.go b/openapi3/openapi3_test.go
index 9892948..3b68c16 100644
--- a/openapi3/openapi3_test.go
+++ b/openapi3/openapi3_test.go
@@ -82,18 +82,9 @@ func TestRefsYAML(t *testing.T) {
 	require.NoError(t, err)
 	dataB, err := yaml.Marshal(docB)
 	require.NoError(t, err)
-	eqYAML(t, data, specYAML)
-	eqYAML(t, data, dataA)
-	eqYAML(t, data, dataB)
-}
-
-func eqYAML(t *testing.T, expected, actual []byte) {
-	var e, a interface{}
-	err := yaml.Unmarshal(expected, &e)
-	require.NoError(t, err)
-	err = yaml.Unmarshal(actual, &a)
-	require.NoError(t, err)
-	require.Equal(t, e, a)
+	require.YAMLEq(t, string(data), string(specYAML))
+	require.YAMLEq(t, string(data), string(dataA))
+	require.YAMLEq(t, string(data), string(dataB))
 }
 
 var specYAML = []byte(`
diff --git a/openapi3/testdata/issue241.yml b/openapi3/testdata/issue241.yml
index 07609c1..1bcd73d 100644
--- a/openapi3/testdata/issue241.yml
+++ b/openapi3/testdata/issue241.yml
@@ -1,15 +1,15 @@
-openapi: 3.0.3
 components:
   schemas:
     FooBar:
-      type: object
       properties:
         type_url:
           type: string
         value:
-          type: string
           format: byte
+          type: string
+      type: object
 info:
   title: sample
   version: version not set
+openapi: 3.0.3
 paths: {}
diff --git a/openapi3filter/middleware_test.go b/openapi3filter/middleware_test.go
index 1260ac5..137228c 100644
--- a/openapi3filter/middleware_test.go
+++ b/openapi3filter/middleware_test.go
@@ -2,6 +2,7 @@ package openapi3filter_test
 
 import (
 	"bytes"
+	"context"
 	"encoding/json"
 	"fmt"
 	"io"
@@ -489,7 +490,7 @@ paths:
 	// testing a service against its spec in development and CI. In production,
 	// availability may be more important than strictness.
 	v := openapi3filter.NewValidator(router, openapi3filter.Strict(true),
-		openapi3filter.OnErr(func(w http.ResponseWriter, status int, code openapi3filter.ErrCode, err error) {
+		openapi3filter.OnErr(func(_ context.Context, w http.ResponseWriter, status int, code openapi3filter.ErrCode, err error) {
 			// Customize validation error responses to use JSON
 			w.Header().Set("Content-Type", "application/json")
 			w.WriteHeader(status)