Repository: getkin/kin-openapi
Pull request #627 (2022-10-07 15:19:40)

Add SIMITGROUP`s repo to dependants shortlist
Fixes https://github.com/getkin/kin-openapi/issues/606


Patch:
diff --git a/README.md b/README.md
index 850876f..9d2cd01 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,7 @@ Here's some projects that depend on _kin-openapi_:
   * [github.com/goadesign/goa](https://github.com/goadesign/goa) - "Design-based APIs and microservices in Go"
   * [github.com/hashicorp/nomad-openapi](https://github.com/hashicorp/nomad-openapi) - "Nomad is an easy-to-use, flexible, and performant workload orchestrator that can deploy a mix of microservice, batch, containerized, and non-containerized applications. Nomad is easy to operate and scale and has native Consul and Vault integrations."
   * [gitlab.com/jamietanna/httptest-openapi](https://gitlab.com/jamietanna/httptest-openapi) ([*blog post*](https://www.jvt.me/posts/2022/05/22/go-openapi-contract-test/)) - "Go OpenAPI Contract Verification for use with `net/http`"
+  * [github.com/SIMITGROUP/openapigenerator](https://github.com/SIMITGROUP/openapigenerator) - "Openapi v3 microservices generator"
   * (Feel free to add your project by [creating an issue](https://github.com/getkin/kin-openapi/issues/new) or a pull request)
 
 ## Alternatives
diff --git a/openapi3/components.go b/openapi3/components.go
index 3f883fa..b7ad11c 100644
--- a/openapi3/components.go
+++ b/openapi3/components.go
@@ -49,10 +49,10 @@ func (components *Components) Validate(ctx context.Context) (err error) {
 	for _, k := range schemas {
 		v := components.Schemas[k]
 		if err = ValidateIdentifier(k); err != nil {
-			return
+			return fmt.Errorf("schema %q: %w", k, err)
 		}
 		if err = v.Validate(ctx); err != nil {
-			return
+			return fmt.Errorf("schema %q: %w", k, err)
 		}
 	}
 
@@ -64,10 +64,10 @@ func (components *Components) Validate(ctx context.Context) (err error) {
 	for _, k := range parameters {
 		v := components.Parameters[k]
 		if err = ValidateIdentifier(k); err != nil {
-			return
+			return fmt.Errorf("parameter %q: %w", k, err)
 		}
 		if err = v.Validate(ctx); err != nil {
-			return
+			return fmt.Errorf("parameter %q: %w", k, err)
 		}
 	}
 
@@ -79,10 +79,10 @@ func (components *Components) Validate(ctx context.Context) (err error) {
 	for _, k := range requestBodies {
 		v := components.RequestBodies[k]
 		if err = ValidateIdentifier(k); err != nil {
-			return
+			return fmt.Errorf("request body %q: %w", k, err)
 		}
 		if err = v.Validate(ctx); err != nil {
-			return
+			return fmt.Errorf("request body %q: %w", k, err)
 		}
 	}
 
@@ -94,10 +94,10 @@ func (components *Components) Validate(ctx context.Context) (err error) {
 	for _, k := range responses {
 		v := components.Responses[k]
 		if err = ValidateIdentifier(k); err != nil {
-			return
+			return fmt.Errorf("response %q: %w", k, err)
 		}
 		if err = v.Validate(ctx); err != nil {
-			return
+			return fmt.Errorf("response %q: %w", k, err)
 		}
 	}
 
@@ -109,10 +109,10 @@ func (components *Components) Validate(ctx context.Context) (err error) {
 	for _, k := range headers {
 		v := components.Headers[k]
 		if err = ValidateIdentifier(k); err != nil {
-			return
+			return fmt.Errorf("header %q: %w", k, err)
 		}
 		if err = v.Validate(ctx); err != nil {
-			return
+			return fmt.Errorf("header %q: %w", k, err)
 		}
 	}
 
@@ -124,10 +124,10 @@ func (components *Components) Validate(ctx context.Context) (err error) {
 	for _, k := range securitySchemes {
 		v := components.SecuritySchemes[k]
 		if err = ValidateIdentifier(k); err != nil {
-			return
+			return fmt.Errorf("security scheme %q: %w", k, err)
 		}
 		if err = v.Validate(ctx); err != nil {
-			return
+			return fmt.Errorf("security scheme %q: %w", k, err)
 		}
 	}
 
@@ -139,10 +139,10 @@ func (components *Components) Validate(ctx context.Context) (err error) {
 	for _, k := range examples {
 		v := components.Examples[k]
 		if err = ValidateIdentifier(k); err != nil {
-			return
+			return fmt.Errorf("example %q: %w", k, err)
 		}
 		if err = v.Validate(ctx); err != nil {
-			return fmt.Errorf("%s: %w", k, err)
+			return fmt.Errorf("example %q: %w", k, err)
 		}
 	}
 
@@ -154,10 +154,10 @@ func (components *Components) Validate(ctx context.Context) (err error) {
 	for _, k := range links {
 		v := components.Links[k]
 		if err = ValidateIdentifier(k); err != nil {
-			return
+			return fmt.Errorf("link %q: %w", k, err)
 		}
 		if err = v.Validate(ctx); err != nil {
-			return
+			return fmt.Errorf("link %q: %w", k, err)
 		}
 	}
 
@@ -169,10 +169,10 @@ func (components *Components) Validate(ctx context.Context) (err error) {
 	for _, k := range callbacks {
 		v := components.Callbacks[k]
 		if err = ValidateIdentifier(k); err != nil {
-			return
+			return fmt.Errorf("callback %q: %w", k, err)
 		}
 		if err = v.Validate(ctx); err != nil {
-			return
+			return fmt.Errorf("callback %q: %w", k, err)
 		}
 	}
 
diff --git a/openapi3/example.go b/openapi3/example.go
index e63c78f..2161b68 100644
--- a/openapi3/example.go
+++ b/openapi3/example.go
@@ -60,7 +60,7 @@ func (example *Example) Validate(ctx context.Context) error {
 		return errors.New("value and externalValue are mutually exclusive")
 	}
 	if example.Value == nil && example.ExternalValue == "" {
-		return errors.New("example has no value or externalValue field")
+		return errors.New("no value or externalValue field")
 	}
 
 	return nil
diff --git a/openapi3/media_type.go b/openapi3/media_type.go
index 4269a4e..1ae7c99 100644
--- a/openapi3/media_type.go
+++ b/openapi3/media_type.go
@@ -94,7 +94,7 @@ func (mediaType *MediaType) Validate(ctx context.Context) error {
 
 		if example := mediaType.Example; example != nil {
 			if err := validateExampleValue(example, schema.Value); err != nil {
-				return err
+				return fmt.Errorf("invalid example: %w", err)
 			}
 		}
 
@@ -107,10 +107,10 @@ func (mediaType *MediaType) Validate(ctx context.Context) error {
 			for _, k := range names {
 				v := examples[k]
 				if err := v.Validate(ctx); err != nil {
-					return fmt.Errorf("%s: %w", k, err)
+					return fmt.Errorf("example %s: %w", k, err)
 				}
 				if err := validateExampleValue(v.Value.Value, schema.Value); err != nil {
-					return fmt.Errorf("%s: %w", k, err)
+					return fmt.Errorf("example %s: %w", k, err)
 				}
 			}
 		}
diff --git a/openapi3/parameter.go b/openapi3/parameter.go
index 6e2dbca..73a39a5 100644
--- a/openapi3/parameter.go
+++ b/openapi3/parameter.go
@@ -323,7 +323,7 @@ func (parameter *Parameter) Validate(ctx context.Context) error {
 		}
 		if example := parameter.Example; example != nil {
 			if err := validateExampleValue(example, schema.Value); err != nil {
-				return err
+				return fmt.Errorf("invalid example: %w", err)
 			}
 		} else if examples := parameter.Examples; examples != nil {
 			names := make([]string, 0, len(examples))
diff --git a/openapi3/schema.go b/openapi3/schema.go
index e9b6617..641ce85 100644
--- a/openapi3/schema.go
+++ b/openapi3/schema.go
@@ -763,13 +763,13 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error)
 
 	if v := schema.Default; v != nil {
 		if err := schema.VisitJSON(v); err != nil {
-			return fmt.Errorf("invalid schema default: %w", err)
+			return fmt.Errorf("invalid default: %w", err)
 		}
 	}
 
 	if x := schema.Example; x != nil && !validationOpts.ExamplesValidationDisabled {
 		if err := validateExampleValue(x, schema); err != nil {
-			return fmt.Errorf("invalid schema example: %w", err)
+			return fmt.Errorf("invalid example: %w", err)
 		}
 	}
 
diff --git a/routers/legacy/router.go b/routers/legacy/router.go
index fb8d462..74e3873 100644
--- a/routers/legacy/router.go
+++ b/routers/legacy/router.go
@@ -58,8 +58,8 @@ type Router struct {
 //
 // If the given OpenAPIv3 document has servers, router will use them.
 // All operations of the document will be added to the router.
-func NewRouter(doc *openapi3.T) (routers.Router, error) {
-	if err := doc.Validate(context.Background()); err != nil {
+func NewRouter(doc *openapi3.T, opts ...openapi3.ValidationOption) (routers.Router, error) {
+	if err := doc.Validate(context.Background(), opts...); err != nil {
 		return nil, fmt.Errorf("validating OpenAPI failed: %w", err)
 	}
 	router := &Router{doc: doc}


Test patch:
diff --git a/openapi3/example_validation_test.go b/openapi3/example_validation_test.go
index 177360c..f6a495a 100644
--- a/openapi3/example_validation_test.go
+++ b/openapi3/example_validation_test.go
@@ -41,7 +41,7 @@ func TestExamplesSchemaValidation(t *testing.T) {
 			parametersExample: `
           example: abcd
    `,
-			errContains: "invalid paths",
+			errContains: "invalid path /user: invalid operation POST: invalid example",
 		},
 		{
 			name: "valid_parameter_example",
@@ -64,7 +64,7 @@ func TestExamplesSchemaValidation(t *testing.T) {
         email: bad
         password: short
    `,
-			errContains: "invalid paths: invalid path /user: invalid operation POST: BadUser",
+			errContains: "invalid paths: invalid path /user: invalid operation POST: example BadUser",
 		},
 		{
 			name: "valid_component_examples",
@@ -90,7 +90,7 @@ func TestExamplesSchemaValidation(t *testing.T) {
               email: bad
               password: short
    `,
-			errContains: "invalid paths",
+			errContains: "invalid path /user: invalid operation POST: invalid example",
 		},
 		{
 			name: "valid_mediatype_examples",
@@ -109,7 +109,7 @@ func TestExamplesSchemaValidation(t *testing.T) {
         email: good@email.com
         # missing password
    `,
-			errContains: "invalid schema example",
+			errContains: "schema \"CreateUserRequest\": invalid example",
 		},
 		{
 			name: "valid_schema_request_example",
@@ -127,7 +127,7 @@ func TestExamplesSchemaValidation(t *testing.T) {
         user_id: 1
         # missing access_token
    `,
-			errContains: "invalid schema example",
+			errContains: "schema \"CreateUserResponse\": invalid example",
 		},
 		{
 			name: "valid_schema_response_example",
@@ -278,7 +278,7 @@ func TestExampleObjectValidation(t *testing.T) {
               email: real@email.com
               password: validpassword
 `,
-			errContains: "example and examples are mutually exclusive",
+			errContains: "invalid path /user: invalid operation POST: example and examples are mutually exclusive",
 			componentExamples: `
   examples:
     BadUser:
@@ -295,7 +295,7 @@ func TestExampleObjectValidation(t *testing.T) {
     BadUser:
       description: empty user example
 `,
-			errContains: "example has no value or externalValue field",
+			errContains: "invalid components: example \"BadUser\": no value or externalValue field",
 		},
 		{
 			name: "value_externalValue_mutual_exclusion",
@@ -308,7 +308,7 @@ func TestExampleObjectValidation(t *testing.T) {
         password: validpassword
       externalValue: 'http://example.com/examples/example'
 `,
-			errContains: "value and externalValue are mutually exclusive",
+			errContains: "invalid components: example \"BadUser\": value and externalValue are mutually exclusive",
 		},
 	}
 
diff --git a/openapi3/issue601_test.go b/openapi3/issue601_test.go
index 420ac9d..ef841c2 100644
--- a/openapi3/issue601_test.go
+++ b/openapi3/issue601_test.go
@@ -18,7 +18,7 @@ func TestIssue601(t *testing.T) {
 	require.NoError(t, err)
 
 	err = doc.Validate(sl.Context)
-	require.Contains(t, err.Error(), `invalid components: invalid schema example: Error at "/type": property "type" is missing`)
+	require.Contains(t, err.Error(), `invalid components: schema "DiscoveryResult": invalid example: Error at "/type": property "type" is missing`)
 	require.Contains(t, err.Error(), `| Error at "/nsid": property "nsid" is missing`)
 
 	err = doc.Validate(sl.Context, DisableExamplesValidation())
diff --git a/routers/issue356_test.go b/routers/issue356_test.go
index 3e4b9fa..de9f06b 100644
--- a/routers/issue356_test.go
+++ b/routers/issue356_test.go
@@ -68,8 +68,11 @@ paths:
 		require.NoError(t, err)
 		err = doc.Validate(context.Background())
 		require.NoError(t, err)
+		gorillamuxNewRouterWrapped := func(doc *openapi3.T, opts ...openapi3.ValidationOption) (routers.Router, error) {
+			return gorillamux.NewRouter(doc)
+		}
 
-		for i, newRouter := range []func(*openapi3.T) (routers.Router, error){gorillamux.NewRouter, legacy.NewRouter} {
+		for i, newRouter := range []func(*openapi3.T, ...openapi3.ValidationOption) (routers.Router, error){gorillamuxNewRouterWrapped, legacy.NewRouter} {
 			t.Logf("using NewRouter from %s", map[int]string{0: "gorillamux", 1: "legacy"}[i])
 			router, err := newRouter(doc)
 			require.NoError(t, err)
diff --git a/routers/legacy/router_test.go b/routers/legacy/router_test.go
index d4779f5..e9b8759 100644
--- a/routers/legacy/router_test.go
+++ b/routers/legacy/router_test.go
@@ -193,4 +193,21 @@ func TestRouter(t *testing.T) {
 		require.Nil(t, route)
 		require.Nil(t, pathParams)
 	}
+
+	schema := &openapi3.Schema{
+		Type:    "string",
+		Example: 3,
+	}
+	content := openapi3.NewContentWithJSONSchema(schema)
+	responses := openapi3.NewResponses()
+	responses["default"].Value.Content = content
+	doc.Paths["/withExamples"] = &openapi3.PathItem{
+		Get: &openapi3.Operation{Responses: responses},
+	}
+	err = doc.Validate(context.Background())
+	require.Error(t, err)
+	r, err = NewRouter(doc)
+	require.Error(t, err)
+	r, err = NewRouter(doc, openapi3.DisableExamplesValidation())
+	require.NoError(t, err)
 }