Repository: getkin/kin-openapi
Pull request #1041 (2024-12-11 10:53:46)

openapi3filter: Simplify ValidateRequest implementation
The PR refactors `openapi3filter.ValidateRequest`. If `options.MultiError == true`, the function compares `err != nil` twice instead of once.


Patch:
diff --git a/.github/docs/openapi3.txt b/.github/docs/openapi3.txt
index 4729e0c..47aaead 100644
--- a/.github/docs/openapi3.txt
+++ b/.github/docs/openapi3.txt
@@ -35,10 +35,10 @@ const (
 	FormatOfStringByte = `(^$|^[a-zA-Z0-9+/\-_]*=*$)`
 
 	// FormatOfStringDate is a RFC3339 date format regexp, for example "2017-07-21".
-	FormatOfStringDate = `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)$`
+	FormatOfStringDate = `^[0-9]{4}-(0[1-9]|10|11|12)-(0[1-9]|[12][0-9]|3[01])$`
 
 	// FormatOfStringDateTime is a RFC3339 date-time format regexp, for example "2017-07-21T17:32:28Z".
-	FormatOfStringDateTime = `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`
+	FormatOfStringDateTime = `^[0-9]{4}-(0[1-9]|10|11|12)-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`
 )
 const (
 	SerializationSimple         = "simple"
diff --git a/.github/docs/openapi3filter.txt b/.github/docs/openapi3filter.txt
index d44ba5a..1eb4d41 100644
--- a/.github/docs/openapi3filter.txt
+++ b/.github/docs/openapi3filter.txt
@@ -93,7 +93,7 @@ func ValidateParameter(ctx context.Context, input *RequestValidationInput, param
     defined. The function returns RequestError with a openapi3.SchemaError cause
     when a value is invalid by JSON schema.
 
-func ValidateRequest(ctx context.Context, input *RequestValidationInput) (err error)
+func ValidateRequest(ctx context.Context, input *RequestValidationInput) error
     ValidateRequest is used to validate the given input according to previous
     loaded OpenAPIv3 spec. If the input does not match the OpenAPIv3 spec,
     a non-nil error will be returned.
diff --git a/cmd/validate/main.go b/cmd/validate/main.go
index 874f30c..7519407 100644
--- a/cmd/validate/main.go
+++ b/cmd/validate/main.go
@@ -6,7 +6,7 @@ import (
 	"os"
 	"strings"
 
-	"github.com/invopop/yaml"
+	"github.com/oasdiff/yaml"
 
 	"github.com/getkin/kin-openapi/openapi2"
 	"github.com/getkin/kin-openapi/openapi3"
diff --git a/go.mod b/go.mod
index 7d37032..4855060 100644
--- a/go.mod
+++ b/go.mod
@@ -2,18 +2,14 @@ module github.com/getkin/kin-openapi
 
 go 1.22.5
 
-replace gopkg.in/yaml.v3 => github.com/oasdiff/yaml3 v0.0.0-20240920135353-c185dc6ea7c6
-
-replace github.com/invopop/yaml => github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3
-
 require (
 	github.com/go-openapi/jsonpointer v0.21.0
 	github.com/gorilla/mux v1.8.0
-	github.com/invopop/yaml v0.3.1
 	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
+	github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80
+	github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349
 	github.com/perimeterx/marshmallow v1.1.5
 	github.com/stretchr/testify v1.9.0
-	gopkg.in/yaml.v3 v3.0.1
 )
 
 require (
@@ -23,4 +19,5 @@ require (
 	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/rogpeppe/go-internal v1.12.0 // indirect
+	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index f9643cd..422452c 100644
--- a/go.sum
+++ b/go.sum
@@ -18,10 +18,10 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
-github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3 h1:nqCxALSUgWobWkFGIrhLRzR/bpImQdGj+3JS4/scTJo=
-github.com/oasdiff/yaml v0.0.0-20240920191703-3e5a9fb5bdf3/go.mod h1:AOyUNV9ElKz7EEZeBm/48U54UtjtgCMT9fFbZEsClQc=
-github.com/oasdiff/yaml3 v0.0.0-20240920135353-c185dc6ea7c6 h1:+ZsuDTdapTJxfMQk7SOJiNMg0v36pui01L7FEO615r8=
-github.com/oasdiff/yaml3 v0.0.0-20240920135353-c185dc6ea7c6/go.mod h1:lqlOfJRrYpgeWHQj+ky2tf7UJ3PzgHTHRQEpc90nbp0=
+github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80 h1:nZspmSkneBbtxU9TopEAE0CY+SBJLxO8LPUlw2vG4pU=
+github.com/oasdiff/yaml v0.0.0-20241210131133-6b86fb107d80/go.mod h1:7tFDb+Y51LcDpn26GccuUgQXUk6t0CXZsivKjyimYX8=
+github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349 h1:t05Ww3DxZutOqbMN+7OIuqDwXbhl32HiZGpLy26BAPc=
+github.com/oasdiff/yaml3 v0.0.0-20241210130736-a94c01f36349/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
 github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
 github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -32,5 +32,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
 github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/openapi2/marsh.go b/openapi2/marsh.go
index 1a4b0d1..1745734 100644
--- a/openapi2/marsh.go
+++ b/openapi2/marsh.go
@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/invopop/yaml"
+	"github.com/oasdiff/yaml"
 )
 
 func unmarshalError(jsonUnmarshalErr error) error {
diff --git a/openapi3/marsh.go b/openapi3/marsh.go
index 9fdc6df..2f00828 100644
--- a/openapi3/marsh.go
+++ b/openapi3/marsh.go
@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/invopop/yaml"
+	"github.com/oasdiff/yaml"
 )
 
 func unmarshalError(jsonUnmarshalErr error) error {
diff --git a/openapi3/schema_formats.go b/openapi3/schema_formats.go
index 1b76707..489105b 100644
--- a/openapi3/schema_formats.go
+++ b/openapi3/schema_formats.go
@@ -41,10 +41,10 @@ const (
 	FormatOfStringByte = `(^$|^[a-zA-Z0-9+/\-_]*=*$)`
 
 	// FormatOfStringDate is a RFC3339 date format regexp, for example "2017-07-21".
-	FormatOfStringDate = `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)$`
+	FormatOfStringDate = `^[0-9]{4}-(0[1-9]|10|11|12)-(0[1-9]|[12][0-9]|3[01])$`
 
 	// FormatOfStringDateTime is a RFC3339 date-time format regexp, for example "2017-07-21T17:32:28Z".
-	FormatOfStringDateTime = `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`
+	FormatOfStringDateTime = `^[0-9]{4}-(0[1-9]|10|11|12)-(0[1-9]|[12][0-9]|3[01])T([0-1][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$`
 )
 
 func init() {
diff --git a/openapi3filter/req_resp_decoder.go b/openapi3filter/req_resp_decoder.go
index 19e3609..c77289f 100644
--- a/openapi3filter/req_resp_decoder.go
+++ b/openapi3filter/req_resp_decoder.go
@@ -17,7 +17,7 @@ import (
 	"strconv"
 	"strings"
 
-	"gopkg.in/yaml.v3"
+	"github.com/oasdiff/yaml3"
 
 	"github.com/getkin/kin-openapi/openapi3"
 )
diff --git a/openapi3filter/validate_request.go b/openapi3filter/validate_request.go
index bf4771a..a28fbcc 100644
--- a/openapi3filter/validate_request.go
+++ b/openapi3filter/validate_request.go
@@ -29,7 +29,7 @@ var ErrInvalidEmptyValue = errors.New("empty value is not allowed")
 //
 // Note: One can tune the behavior of uniqueItems: true verification
 // by registering a custom function with openapi3.RegisterArrayUniqueItemsChecker
-func ValidateRequest(ctx context.Context, input *RequestValidationInput) (err error) {
+func ValidateRequest(ctx context.Context, input *RequestValidationInput) error {
 	var me openapi3.MultiError
 
 	options := input.Options
@@ -49,10 +49,10 @@ func ValidateRequest(ctx context.Context, input *RequestValidationInput) (err er
 		security = &route.Spec.Security
 	}
 	if security != nil {
-		if err = ValidateSecurityRequirements(ctx, input, *security); err != nil && !options.MultiError {
-			return
-		}
-		if err != nil {
+		if err := ValidateSecurityRequirements(ctx, input, *security); err != nil {
+			if !options.MultiError {
+				return err
+			}
 			me = append(me, err)
 		}
 	}
@@ -66,10 +66,10 @@ func ValidateRequest(ctx context.Context, input *RequestValidationInput) (err er
 			}
 		}
 
-		if err = ValidateParameter(ctx, input, parameter); err != nil && !options.MultiError {
-			return
-		}
-		if err != nil {
+		if err := ValidateParameter(ctx, input, parameter); err != nil {
+			if !options.MultiError {
+				return err
+			}
 			me = append(me, err)
 		}
 	}
@@ -79,10 +79,10 @@ func ValidateRequest(ctx context.Context, input *RequestValidationInput) (err er
 		if options.ExcludeRequestQueryParams && parameter.Value.In == openapi3.ParameterInQuery {
 			continue
 		}
-		if err = ValidateParameter(ctx, input, parameter.Value); err != nil && !options.MultiError {
-			return
-		}
-		if err != nil {
+		if err := ValidateParameter(ctx, input, parameter.Value); err != nil {
+			if !options.MultiError {
+				return err
+			}
 			me = append(me, err)
 		}
 	}
@@ -90,10 +90,10 @@ func ValidateRequest(ctx context.Context, input *RequestValidationInput) (err er
 	// RequestBody
 	requestBody := operation.RequestBody
 	if requestBody != nil && !options.ExcludeRequestBody {
-		if err = ValidateRequestBody(ctx, input, requestBody.Value); err != nil && !options.MultiError {
-			return
-		}
-		if err != nil {
+		if err := ValidateRequestBody(ctx, input, requestBody.Value); err != nil {
+			if !options.MultiError {
+				return err
+			}
 			me = append(me, err)
 		}
 	}
@@ -101,7 +101,7 @@ func ValidateRequest(ctx context.Context, input *RequestValidationInput) (err er
 	if len(me) > 0 {
 		return me
 	}
-	return
+	return nil
 }
 
 // appendToQueryValues adds to query parameters each value in the provided slice
@@ -114,7 +114,7 @@ func appendToQueryValues[T any](q url.Values, parameterName string, v []T) {
 // populateDefaultQueryParameters populates default values inside query parameters, while ensuring types are respected
 func populateDefaultQueryParameters(q url.Values, parameterName string, value any) {
 	switch t := value.(type) {
-	case []interface{}:
+	case []any:
 		appendToQueryValues(q, parameterName, t)
 	default:
 		q.Add(parameterName, fmt.Sprintf("%v", value))


Test patch:
diff --git a/openapi2/openapi2_test.go b/openapi2/openapi2_test.go
index 8a6bf96..d1b3aa5 100644
--- a/openapi2/openapi2_test.go
+++ b/openapi2/openapi2_test.go
@@ -6,7 +6,7 @@ import (
 	"os"
 	"reflect"
 
-	"github.com/invopop/yaml"
+	"github.com/oasdiff/yaml"
 
 	"github.com/getkin/kin-openapi/openapi2"
 )
diff --git a/openapi2conv/issue187_test.go b/openapi2conv/issue187_test.go
index ffd020b..4cec875 100644
--- a/openapi2conv/issue187_test.go
+++ b/openapi2conv/issue187_test.go
@@ -5,7 +5,7 @@ import (
 	"encoding/json"
 	"testing"
 
-	"github.com/invopop/yaml"
+	"github.com/oasdiff/yaml"
 	"github.com/stretchr/testify/require"
 
 	"github.com/getkin/kin-openapi/openapi2"
diff --git a/openapi2conv/issue558_test.go b/openapi2conv/issue558_test.go
index 2067301..b7fb9dc 100644
--- a/openapi2conv/issue558_test.go
+++ b/openapi2conv/issue558_test.go
@@ -3,7 +3,7 @@ package openapi2conv
 import (
 	"testing"
 
-	"github.com/invopop/yaml"
+	"github.com/oasdiff/yaml"
 	"github.com/stretchr/testify/require"
 )
 
diff --git a/openapi3/additionalProperties_test.go b/openapi3/additionalProperties_test.go
index 7a9ec74..46cf0db 100644
--- a/openapi3/additionalProperties_test.go
+++ b/openapi3/additionalProperties_test.go
@@ -6,8 +6,8 @@ import (
 	"os"
 	"testing"
 
+	"github.com/oasdiff/yaml3"
 	"github.com/stretchr/testify/require"
-	"gopkg.in/yaml.v3"
 
 	"github.com/getkin/kin-openapi/openapi3"
 )
diff --git a/openapi3/datetime_schema_test.go b/openapi3/datetime_schema_test.go
new file mode 100644
index 0000000..fec6057
--- /dev/null
+++ b/openapi3/datetime_schema_test.go
@@ -0,0 +1,167 @@
+package openapi3
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+var DateSpec = []byte(`
+components:
+  schemas:
+    Server:
+      properties:
+        date:
+          $ref: "#/components/schemas/timestamp"
+        name:
+          type: string
+      type: object
+    timestamp:
+      type: string
+      format: date
+openapi: "3.0.1"
+paths: {}
+info:
+  version: 1.1.1
+  title: title
+`[1:])
+
+var DateTimeSpec = []byte(`
+components:
+  schemas:
+    Server:
+      properties:
+        datetime:
+          $ref: "#/components/schemas/timestamp"
+        name:
+          type: string
+      type: object
+    timestamp:
+      type: string
+      format: date-time
+openapi: "3.0.1"
+paths: {}
+info:
+  version: 1.1.1
+  title: title
+`[1:])
+
+func TestDateZeroMonth(t *testing.T) {
+	loader := NewLoader()
+	doc, err := loader.LoadFromData(DateSpec)
+	require.NoError(t, err)
+
+	err = doc.Validate(loader.Context)
+	require.NoError(t, err)
+
+	err = doc.Components.Schemas["Server"].Value.VisitJSON(map[string]any{
+		"name": "kin-openapi",
+		"date": "2001-00-03",
+	})
+	require.EqualError(t, err, `Error at "/date": string doesn't match the format "date": string doesn't match pattern "`+FormatOfStringDate+`"`)
+}
+
+func TestDateZeroDay(t *testing.T) {
+	loader := NewLoader()
+	doc, err := loader.LoadFromData(DateSpec)
+	require.NoError(t, err)
+
+	err = doc.Validate(loader.Context)
+	require.NoError(t, err)
+
+	err = doc.Components.Schemas["Server"].Value.VisitJSON(map[string]any{
+		"name": "kin-openapi",
+		"date": "2001-02-00",
+	})
+	require.EqualError(t, err, `Error at "/date": string doesn't match the format "date": string doesn't match pattern "`+FormatOfStringDate+`"`)
+}
+
+func TestDateTimeZeroMonth(t *testing.T) {
+	loader := NewLoader()
+	doc, err := loader.LoadFromData(DateTimeSpec)
+	require.NoError(t, err)
+
+	err = doc.Validate(loader.Context)
+	require.NoError(t, err)
+
+	err = doc.Components.Schemas["Server"].Value.VisitJSON(map[string]any{
+		"name":     "kin-openapi",
+		"datetime": "2001-00-03T04:05:06.789Z",
+	})
+	require.EqualError(t, err, `Error at "/datetime": string doesn't match the format "date-time": string doesn't match pattern "`+FormatOfStringDateTime+`"`)
+}
+
+func TestDateTimeZeroDay(t *testing.T) {
+	loader := NewLoader()
+	doc, err := loader.LoadFromData(DateTimeSpec)
+	require.NoError(t, err)
+
+	err = doc.Validate(loader.Context)
+	require.NoError(t, err)
+
+	err = doc.Components.Schemas["Server"].Value.VisitJSON(map[string]any{
+		"name":     "kin-openapi",
+		"datetime": "2001-02-00T04:05:06.789Z",
+	})
+	require.EqualError(t, err, `Error at "/datetime": string doesn't match the format "date-time": string doesn't match pattern "`+FormatOfStringDateTime+`"`)
+}
+
+func TestDateTimeLeapSecond(t *testing.T) {
+	loader := NewLoader()
+	doc, err := loader.LoadFromData(DateTimeSpec)
+	require.NoError(t, err)
+
+	err = doc.Validate(loader.Context)
+	require.NoError(t, err)
+
+	err = doc.Components.Schemas["Server"].Value.VisitJSON(map[string]any{
+		"name":     "kin-openapi",
+		"datetime": "2016-12-31T23:59:60.000Z", // exact time of the most recent leap second
+	})
+	require.NoError(t, err)
+}
+
+func TestDateTimeHourOutOfBounds(t *testing.T) {
+	loader := NewLoader()
+	doc, err := loader.LoadFromData(DateTimeSpec)
+	require.NoError(t, err)
+
+	err = doc.Validate(loader.Context)
+	require.NoError(t, err)
+
+	err = doc.Components.Schemas["Server"].Value.VisitJSON(map[string]any{
+		"name":     "kin-openapi",
+		"datetime": "2016-12-31T24:00:00.000Z",
+	})
+	require.EqualError(t, err, `Error at "/datetime": string doesn't match the format "date-time": string doesn't match pattern "`+FormatOfStringDateTime+`"`)
+}
+
+func TestDateTimeMinuteOutOfBounds(t *testing.T) {
+	loader := NewLoader()
+	doc, err := loader.LoadFromData(DateTimeSpec)
+	require.NoError(t, err)
+
+	err = doc.Validate(loader.Context)
+	require.NoError(t, err)
+
+	err = doc.Components.Schemas["Server"].Value.VisitJSON(map[string]any{
+		"name":     "kin-openapi",
+		"datetime": "2016-12-31T23:60:00.000Z",
+	})
+	require.EqualError(t, err, `Error at "/datetime": string doesn't match the format "date-time": string doesn't match pattern "`+FormatOfStringDateTime+`"`)
+}
+
+func TestDateTimeSecondOutOfBounds(t *testing.T) {
+	loader := NewLoader()
+	doc, err := loader.LoadFromData(DateTimeSpec)
+	require.NoError(t, err)
+
+	err = doc.Validate(loader.Context)
+	require.NoError(t, err)
+
+	err = doc.Components.Schemas["Server"].Value.VisitJSON(map[string]any{
+		"name":     "kin-openapi",
+		"datetime": "2016-12-31T23:59:61.000Z",
+	})
+	require.EqualError(t, err, `Error at "/datetime": string doesn't match the format "date-time": string doesn't match pattern "`+FormatOfStringDateTime+`"`)
+}
diff --git a/openapi3/issue241_test.go b/openapi3/issue241_test.go
index 0b37b0a..9a643ed 100644
--- a/openapi3/issue241_test.go
+++ b/openapi3/issue241_test.go
@@ -5,8 +5,8 @@ import (
 	"os"
 	"testing"
 
+	"github.com/oasdiff/yaml3"
 	"github.com/stretchr/testify/require"
-	"gopkg.in/yaml.v3"
 
 	"github.com/getkin/kin-openapi/openapi3"
 )
diff --git a/openapi3/issue82_test.go b/openapi3/issue82_test.go
index 3bf242b..27b72e2 100644
--- a/openapi3/issue82_test.go
+++ b/openapi3/issue82_test.go
@@ -8,7 +8,7 @@ import (
 )
 
 func TestIssue82(t *testing.T) {
-	payload := map[string]interface{}{
+	payload := map[string]any{
 		"prop1": "val",
 		"prop3": "val",
 	}
diff --git a/openapi3/issue883_test.go b/openapi3/issue883_test.go
index 28d7163..7609e6a 100644
--- a/openapi3/issue883_test.go
+++ b/openapi3/issue883_test.go
@@ -3,9 +3,9 @@ package openapi3_test
 import (
 	"testing"
 
-	invopopYaml "github.com/invopop/yaml"
+	yaml "github.com/oasdiff/yaml"
+	yamlv3 "github.com/oasdiff/yaml3"
 	"github.com/stretchr/testify/require"
-	v3 "gopkg.in/yaml.v3"
 
 	"github.com/getkin/kin-openapi/openapi3"
 )
@@ -38,8 +38,8 @@ paths:
 	require.NoError(t, err)
 	require.NotNil(t, doc.Paths)
 
-	t.Run("Roundtrip invopop/yaml", func(t *testing.T) {
-		justPaths, err := invopopYaml.Marshal(doc.Paths)
+	t.Run("Roundtrip using yaml pkg", func(t *testing.T) {
+		justPaths, err := yaml.Marshal(doc.Paths)
 		require.NoError(t, err)
 		require.NotNil(t, doc.Paths)
 		require.YAMLEq(t, `
@@ -51,13 +51,13 @@ paths:
         description: OK
 `[1:], string(justPaths))
 
-		marshalledYaml, err := invopopYaml.Marshal(doc)
+		marshalledYaml, err := yaml.Marshal(doc)
 		require.NoError(t, err)
 		require.NotNil(t, doc.Paths)
 		require.YAMLEq(t, spec, string(marshalledYaml))
 
 		var newDoc openapi3.T
-		err = invopopYaml.Unmarshal(marshalledYaml, &newDoc)
+		err = yaml.Unmarshal(marshalledYaml, &newDoc)
 		require.NoError(t, err)
 		require.NotNil(t, newDoc.Paths)
 		require.Equal(t, doc, &newDoc)
@@ -76,7 +76,7 @@ paths:
         description: OK
 `[1:], string(justPaths))
 
-		justPaths, err = v3.Marshal(doc.Paths)
+		justPaths, err = yamlv3.Marshal(doc.Paths)
 		require.NoError(t, err)
 		require.NotNil(t, doc.Paths)
 		require.YAMLEq(t, `
@@ -88,14 +88,14 @@ paths:
         description: OK
 `[1:], string(justPaths))
 
-		marshalledYaml, err := v3.Marshal(doc)
+		marshalledYaml, err := yamlv3.Marshal(doc)
 		require.NoError(t, err)
 		require.NotNil(t, doc.Paths)
 		require.YAMLEq(t, spec, string(marshalledYaml))
 
-		t.Skip("TODO: impl https://pkg.go.dev/gopkg.in/yaml.v3#Unmarshaler on maplike types")
+		t.Skip("TODO: impl https://pkg.go.dev/github.com/oasdiff/yaml3#Unmarshaler on maplike types")
 		var newDoc openapi3.T
-		err = v3.Unmarshal(marshalledYaml, &newDoc)
+		err = yamlv3.Unmarshal(marshalledYaml, &newDoc)
 		require.NoError(t, err)
 		require.NotNil(t, newDoc.Paths)
 		require.Equal(t, doc, &newDoc)
diff --git a/openapi3/issue972_test.go b/openapi3/issue972_test.go
index 3575adc..5aaaae2 100644
--- a/openapi3/issue972_test.go
+++ b/openapi3/issue972_test.go
@@ -3,8 +3,8 @@ package openapi3
 import (
 	"testing"
 
+	"github.com/oasdiff/yaml3"
 	"github.com/stretchr/testify/assert"
-	"gopkg.in/yaml.v3"
 )
 
 func TestIssue972(t *testing.T) {
diff --git a/openapi3/openapi3_test.go b/openapi3/openapi3_test.go
index 3b68c16..bb42df5 100644
--- a/openapi3/openapi3_test.go
+++ b/openapi3/openapi3_test.go
@@ -6,7 +6,7 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/invopop/yaml"
+	"github.com/oasdiff/yaml"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
diff --git a/openapi3/refs_issue247_test.go b/openapi3/refs_issue247_test.go
index 62f056d..ae6d0c3 100644
--- a/openapi3/refs_issue247_test.go
+++ b/openapi3/refs_issue247_test.go
@@ -120,7 +120,7 @@ components:
 	require.NoError(t, err)
 
 	var ptr jsonpointer.Pointer
-	var v interface{}
+	var v any
 	var kind reflect.Kind
 
 	ptr, err = jsonpointer.New("/paths")
diff --git a/openapi3/schema_issue492_test.go b/openapi3/schema_issue492_test.go
index 2fdfcbc..1515672 100644
--- a/openapi3/schema_issue492_test.go
+++ b/openapi3/schema_issue492_test.go
@@ -46,5 +46,5 @@ info:
 		"name": "kin-openapi",
 		"time": "2001-02-03T04:05:06:789Z",
 	})
-	require.ErrorContains(t, err, `Error at "/time": string doesn't match the format "date-time": string doesn't match pattern "^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?(Z|(\+|-)[0-9]{2}:[0-9]{2})?$"`)
+	require.EqualError(t, err, `Error at "/time": string doesn't match the format "date-time": string doesn't match pattern "`+FormatOfStringDateTime+`"`)
 }
diff --git a/openapi3/schema_test.go b/openapi3/schema_test.go
index d678361..4332983 100644
--- a/openapi3/schema_test.go
+++ b/openapi3/schema_test.go
@@ -9,8 +9,8 @@ import (
 	"strings"
 	"testing"
 
+	"github.com/oasdiff/yaml3"
 	"github.com/stretchr/testify/require"
-	"gopkg.in/yaml.v3"
 )
 
 type schemaExample struct {