Repository: getkin/kin-openapi
Pull request #493 (2022-02-17 18:01:42)

updated date-time string format regexp to fully comply to standard
Fixes the issue with the regExp for date-time described in [issue 492](https://github.com/getkin/kin-openapi/issues/492)


Patch:
diff --git a/openapi2conv/openapi2_conv.go b/openapi2conv/openapi2_conv.go
index 4177f1f..35cf43d 100644
--- a/openapi2conv/openapi2_conv.go
+++ b/openapi2conv/openapi2_conv.go
@@ -1124,17 +1124,33 @@ func FromV3SecurityScheme(doc3 *openapi3.T, ref *openapi3.SecuritySchemeRef) (*o
 		if flows != nil {
 			var flow *openapi3.OAuthFlow
 			// TODO: Is this the right priority? What if multiple defined?
-			if flow = flows.Implicit; flow != nil {
+			switch {
+			case flows.Implicit != nil:
 				result.Flow = "implicit"
-			} else if flow = flows.AuthorizationCode; flow != nil {
+				flow = flows.Implicit
+				result.AuthorizationURL = flow.AuthorizationURL
+
+			case flows.AuthorizationCode != nil:
 				result.Flow = "accessCode"
-			} else if flow = flows.Password; flow != nil {
+				flow = flows.AuthorizationCode
+				result.AuthorizationURL = flow.AuthorizationURL
+				result.TokenURL = flow.TokenURL
+
+			case flows.Password != nil:
 				result.Flow = "password"
-			} else if flow = flows.ClientCredentials; flow != nil {
+				flow = flows.Password
+				result.TokenURL = flow.TokenURL
+
+			case flows.ClientCredentials != nil:
 				result.Flow = "application"
-			} else {
+				flow = flows.ClientCredentials
+				result.TokenURL = flow.TokenURL
+
+			default:
 				return nil, nil
 			}
+
+			result.Scopes = make(map[string]string, len(flow.Scopes))
 			for scope, desc := range flow.Scopes {
 				result.Scopes[scope] = desc
 			}
diff --git a/openapi3/parameter.go b/openapi3/parameter.go
index 2081e4e..a0b8ed1 100644
--- a/openapi3/parameter.go
+++ b/openapi3/parameter.go
@@ -252,6 +252,10 @@ func (value *Parameter) Validate(ctx context.Context) error {
 		return fmt.Errorf("parameter can't have 'in' value %q", value.In)
 	}
 
+	if in == ParameterInPath && !value.Required {
+		return fmt.Errorf("path parameter %q must be required", value.Name)
+	}
+
 	// Validate a parameter's serialization method.
 	sm, err := value.SerializationMethod()
 	if err != nil {
diff --git a/openapi3/schema_formats.go b/openapi3/schema_formats.go
index 8a8a940..29fbd51 100644
--- a/openapi3/schema_formats.go
+++ b/openapi3/schema_formats.go
@@ -90,7 +90,7 @@ func init() {
 	DefineStringFormat("date", `^[0-9]{4}-(0[0-9]|10|11|12)-([0-2][0-9]|30|31)$`)
 
 	// date-time
-	DefineStringFormat("date-time", `^[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})?$`)
+	DefineStringFormat("date-time", `^[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})?$`)
 
 }
 


Test patch:
diff --git a/openapi3/loader_test.go b/openapi3/loader_test.go
index eb29314..384e54d 100644
--- a/openapi3/loader_test.go
+++ b/openapi3/loader_test.go
@@ -412,6 +412,7 @@ paths:
       parameters:
         - name: id,
           in: path
+          required: true
           schema:
             type: string
       responses:
diff --git a/openapi3/schema_issue492_test.go b/openapi3/schema_issue492_test.go
new file mode 100644
index 0000000..535c82a
--- /dev/null
+++ b/openapi3/schema_issue492_test.go
@@ -0,0 +1,41 @@
+package openapi3
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestIssue492(t *testing.T) {
+	spec := []byte(`components:
+  schemas:
+    Server:
+      properties:
+        time:
+          $ref: "#/components/schemas/timestamp"
+        name:
+          type: string
+      type: object
+    timestamp:
+      type: string
+      format: date-time
+openapi: "3.0.1"
+`)
+
+	s, err := NewLoader().LoadFromData(spec)
+	require.NoError(t, err)
+
+	// verify that the expected format works
+	err = s.Components.Schemas["Server"].Value.VisitJSON(map[string]interface{}{
+		"name": "kin-openapi",
+		"time": "2001-02-03T04:05:06.789Z",
+	})
+	require.NoError(t, err)
+
+	// verify that the issue is fixed
+	err = s.Components.Schemas["Server"].Value.VisitJSON(map[string]interface{}{
+		"name": "kin-openapi",
+		"time": "2001-02-03T04:05:06:789Z",
+	})
+	require.EqualError(t, err, "Error at \"/time\": string doesn't match the format \"date-time\" (regular expression \"^[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})?$\")\nSchema:\n  {\n    \"format\": \"date-time\",\n    \"type\": \"string\"\n  }\n\nValue:\n  \"2001-02-03T04:05:06:789Z\"\n")
+}
diff --git a/openapi3filter/req_resp_decoder_test.go b/openapi3filter/req_resp_decoder_test.go
index 34e6371..f40a7a5 100644
--- a/openapi3filter/req_resp_decoder_test.go
+++ b/openapi3filter/req_resp_decoder_test.go
@@ -908,6 +908,7 @@ func TestDecodeParameter(t *testing.T) {
 					path := "/test"
 					if tc.path != "" {
 						path += "/{" + tc.param.Name + "}"
+						tc.param.Required = true
 					}
 
 					info := &openapi3.Info{
diff --git a/openapi3filter/validation_test.go b/openapi3filter/validation_test.go
index d4d0a12..2f7cf80 100644
--- a/openapi3filter/validation_test.go
+++ b/openapi3filter/validation_test.go
@@ -62,9 +62,10 @@ func TestFilter(t *testing.T) {
 					Parameters: openapi3.Parameters{
 						{
 							Value: &openapi3.Parameter{
-								In:     "path",
-								Name:   "pathArg",
-								Schema: openapi3.NewStringSchema().WithMaxLength(2).NewRef(),
+								In:       "path",
+								Name:     "pathArg",
+								Schema:   openapi3.NewStringSchema().WithMaxLength(2).NewRef(),
+								Required: true,
 							},
 						},
 						{