Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP on #230 coming from #318 #412

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
invoke doc.CompileSchemas right after doc.Validate
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
fenollp committed Aug 26, 2021

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 16d5cc18e9f095994d6b16b122ff1eb4fd2c283e
3 changes: 3 additions & 0 deletions openapi3/discriminator_test.go
Original file line number Diff line number Diff line change
@@ -52,5 +52,8 @@ func TestParsingDiscriminator(t *testing.T) {
err = doc.Validate(loader.Context)
require.NoError(t, err)

err = doc.CompileSchemas()
require.NoError(t, err)

require.Equal(t, 2, len(doc.Components.Schemas["MyResponseType"].Value.Discriminator.Mapping))
}
8 changes: 4 additions & 4 deletions openapi3/encoding_test.go
Original file line number Diff line number Diff line change
@@ -16,17 +16,17 @@ func TestEncodingJSON(t *testing.T) {
require.NotEmpty(t, data)

t.Log("Unmarshal *openapi3.Encoding from JSON")
docA := &Encoding{}
err = json.Unmarshal(encodingJSON, &docA)
enc := &Encoding{}
err = json.Unmarshal(encodingJSON, &enc)
require.NoError(t, err)
require.NotEmpty(t, data)

t.Log("Validate *openapi3.Encoding")
err = docA.Validate(context.Background())
err = enc.Validate(context.Background())
require.NoError(t, err)

t.Log("Ensure representations match")
dataA, err := json.Marshal(docA)
dataA, err := json.Marshal(enc)
require.NoError(t, err)
require.JSONEq(t, string(data), string(encodingJSON))
require.JSONEq(t, string(data), string(dataA))
3 changes: 3 additions & 0 deletions openapi3/issue301_test.go
Original file line number Diff line number Diff line change
@@ -16,6 +16,9 @@ func TestIssue301(t *testing.T) {
err = doc.Validate(sl.Context)
require.NoError(t, err)

err = doc.CompileSchemas()
require.NoError(t, err)

transCallbacks := doc.Paths["/trans"].Post.Callbacks["transactionCallback"].Value
require.Equal(t, "object", (*transCallbacks)["http://notificationServer.com?transactionId={$request.body#/id}&email={$request.body#/email}"].Post.RequestBody.
Value.Content["application/json"].Schema.
3 changes: 3 additions & 0 deletions openapi3/issue341_test.go
Original file line number Diff line number Diff line change
@@ -15,6 +15,9 @@ func TestIssue341(t *testing.T) {
err = doc.Validate(sl.Context)
require.NoError(t, err)

err = doc.CompileSchemas()
require.NoError(t, err)

err = sl.ResolveRefsIn(doc, nil)
require.NoError(t, err)

3 changes: 3 additions & 0 deletions openapi3/issue344_test.go
Original file line number Diff line number Diff line change
@@ -16,5 +16,8 @@ func TestIssue344(t *testing.T) {
err = doc.Validate(sl.Context)
require.NoError(t, err)

err = doc.CompileSchemas()
require.NoError(t, err)

require.Equal(t, "string", doc.Components.Schemas["Test"].Value.Properties["test"].Value.Properties["name"].Value.Type)
}
6 changes: 6 additions & 0 deletions openapi3/issue376_test.go
Original file line number Diff line number Diff line change
@@ -35,6 +35,9 @@ info:
err = doc.Validate(loader.Context)
require.NoError(t, err)

err = doc.CompileSchemas()
require.NoError(t, err)

require.Equal(t, "An API", doc.Info.Title)
require.Equal(t, 2, len(doc.Components.Schemas))
require.Equal(t, 0, len(doc.Paths))
@@ -69,6 +72,9 @@ info:
err = doc.Validate(loader.Context)
require.NoError(t, err)

err = doc.CompileSchemas()
require.NoError(t, err)

for propName, propSchema := range doc.Components.Schemas {
ap := propSchema.Value.AdditionalProperties
apa := propSchema.Value.AdditionalPropertiesAllowed
2 changes: 2 additions & 0 deletions openapi3/issue382_test.go
Original file line number Diff line number Diff line change
@@ -12,4 +12,6 @@ func TestOverridingGlobalParametersValidation(t *testing.T) {
require.NoError(t, err)
err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)
}
6 changes: 6 additions & 0 deletions openapi3/loader_empty_response_description_test.go
Original file line number Diff line number Diff line change
@@ -42,6 +42,8 @@ func TestJSONSpecResponseDescriptionEmptiness(t *testing.T) {
t.Log("Empty description provided: valid spec")
err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)
}

{
@@ -55,6 +57,8 @@ func TestJSONSpecResponseDescriptionEmptiness(t *testing.T) {
t.Log("Non-empty description provided: valid spec")
err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)
}

noDescriptionIsInvalid := func(data []byte) *T {
@@ -66,6 +70,8 @@ func TestJSONSpecResponseDescriptionEmptiness(t *testing.T) {
t.Log("No description provided: invalid spec")
err = doc.Validate(loader.Context)
require.Error(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)
return doc
}

2 changes: 2 additions & 0 deletions openapi3/loader_issue212_test.go
Original file line number Diff line number Diff line change
@@ -77,6 +77,8 @@ components:
require.NoError(t, err)
err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)

expected, err := json.Marshal(&Schema{
Type: "object",
3 changes: 3 additions & 0 deletions openapi3/loader_issue220_test.go
Original file line number Diff line number Diff line change
@@ -22,6 +22,9 @@ func TestIssue220(t *testing.T) {
err = doc.Validate(loader.Context)
require.NoError(t, err)

err = doc.CompileSchemas()
require.NoError(t, err)

require.Equal(t, "integer", doc.Paths["/foo"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Properties["bar"].Value.Type)
}
}
2 changes: 2 additions & 0 deletions openapi3/loader_issue235_test.go
Original file line number Diff line number Diff line change
@@ -13,6 +13,8 @@ func TestIssue235OK(t *testing.T) {
require.NoError(t, err)
err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)
}

func TestIssue235CircularDep(t *testing.T) {
3 changes: 3 additions & 0 deletions openapi3/loader_outside_refs_test.go
Original file line number Diff line number Diff line change
@@ -16,5 +16,8 @@ func TestLoadOutsideRefs(t *testing.T) {
err = doc.Validate(loader.Context)
require.NoError(t, err)

err = doc.CompileSchemas()
require.NoError(t, err)

require.Equal(t, "string", doc.Paths["/service"].Get.Responses["200"].Value.Content["application/json"].Schema.Value.Items.Value.AllOf[0].Value.Properties["created_at"].Value.Type)
}
4 changes: 4 additions & 0 deletions openapi3/loader_paths_test.go
Original file line number Diff line number Diff line change
@@ -29,11 +29,15 @@ paths:
loader := NewLoader()
doc, err := loader.LoadFromData([]byte(strings.Replace(spec, "PATH", path, 1)))
require.NoError(t, err)

err = doc.Validate(loader.Context)
if expectedErr != "" {
require.EqualError(t, err, expectedErr)
} else {
require.NoError(t, err)
}

err = doc.CompileSchemas()
require.NoError(t, err)
}
}
8 changes: 7 additions & 1 deletion openapi3/loader_read_from_uri_func_test.go
Original file line number Diff line number Diff line change
@@ -19,8 +19,11 @@ func TestLoaderReadFromURIFunc(t *testing.T) {
doc, err := loader.LoadFromFile("recursiveRef/openapi.yml")
require.NoError(t, err)
require.NotNil(t, doc)
require.NoError(t, doc.Validate(loader.Context))
err = doc.Validate(loader.Context)
require.NoError(t, err)
require.Equal(t, "bar", doc.Paths["/foo"].Get.Responses.Get(200).Value.Content.Get("application/json").Schema.Value.Properties["foo2"].Value.Properties["foo"].Value.Properties["bar"].Value.Example)
err = doc.CompileSchemas()
require.NoError(t, err)
}

type multipleSourceLoaderExample struct {
@@ -67,6 +70,9 @@ func TestResolveSchemaExternalRef(t *testing.T) {
err = doc.Validate(loader.Context)
require.NoError(t, err)

err = doc.CompileSchemas()
require.NoError(t, err)

refRootVisited := doc.Components.Schemas["Root"].Value.AllOf[0]
require.Equal(t, fmt.Sprintf("%s#/components/schemas/External", externalLocation.String()), refRootVisited.Ref)
require.NotNil(t, refRootVisited.Value)
5 changes: 4 additions & 1 deletion openapi3/loader_recursive_ref_test.go
Original file line number Diff line number Diff line change
@@ -12,6 +12,9 @@ func TestLoaderSupportsRecursiveReference(t *testing.T) {
doc, err := loader.LoadFromFile("testdata/recursiveRef/openapi.yml")
require.NoError(t, err)
require.NotNil(t, doc)
require.NoError(t, doc.Validate(loader.Context))
err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)
require.Equal(t, "bar", doc.Paths["/foo"].Get.Responses.Get(200).Value.Content.Get("application/json").Schema.Value.Properties["foo2"].Value.Properties["foo"].Value.Properties["bar"].Value.Example)
}
17 changes: 17 additions & 0 deletions openapi3/loader_test.go
Original file line number Diff line number Diff line change
@@ -66,6 +66,8 @@ paths:
require.Equal(t, &desc, def.Description)
err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)
}

func ExampleLoader() {
@@ -85,6 +87,8 @@ func TestResolveSchemaRef(t *testing.T) {
require.NoError(t, err)
err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)

refAVisited := doc.Components.Schemas["A"].Value.AllOf[0]
require.Equal(t, "#/components/schemas/B", refAVisited.Ref)
@@ -98,6 +102,8 @@ func TestResolveSchemaRefWithNullSchemaRef(t *testing.T) {
require.NoError(t, err)
err = doc.Validate(loader.Context)
require.EqualError(t, err, `invalid paths: found unresolved ref: ""`)
err = doc.CompileSchemas()
require.NoError(t, err)
}

func TestResolveResponseExampleRef(t *testing.T) {
@@ -128,6 +134,8 @@ paths:

err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)

example := doc.Paths["/"].Get.Responses.Get(200).Value.Content.Get("application/json").Examples["test"]
require.NotNil(t, example.Value)
@@ -261,6 +269,8 @@ func TestLoadWithReferenceInReference(t *testing.T) {
require.NotNil(t, doc)
err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)
require.Equal(t, "string", doc.Paths["/api/test/ref/in/ref"].Post.RequestBody.Value.Content["application/json"].Schema.Value.Properties["definition_reference"].Value.Type)
}

@@ -430,6 +440,9 @@ paths:
err = doc.Validate(loader.Context)
require.NoError(t, err)

err = doc.CompileSchemas()
require.NoError(t, err)

response := doc.Paths[`/users/{id}`].Get.Responses.Get(200).Value
link := response.Links[`father`].Value
require.NotNil(t, link)
@@ -497,6 +510,8 @@ paths:
require.NoError(t, err)
err = doc.Validate(loader.Context)
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)
}

func TestServersVariables(t *testing.T) {
@@ -526,6 +541,8 @@ servers:
require.NoError(t, err)
err = doc.Validate(loader.Context)
require.Equal(t, expected, err)
err = doc.CompileSchemas()
require.NoError(t, err)
})
}
}
8 changes: 4 additions & 4 deletions openapi3/media_type_test.go
Original file line number Diff line number Diff line change
@@ -15,17 +15,17 @@ func TestMediaTypeJSON(t *testing.T) {
require.NotEmpty(t, data)

t.Log("Unmarshal *openapi3.MediaType from JSON")
docA := &MediaType{}
err = json.Unmarshal(mediaTypeJSON, &docA)
mt := &MediaType{}
err = json.Unmarshal(mediaTypeJSON, &mt)
require.NoError(t, err)
require.NotEmpty(t, data)

t.Log("Validate *openapi3.MediaType")
err = docA.Validate(context.Background())
err = mt.Validate(context.Background())
require.NoError(t, err)

t.Log("Ensure representations match")
dataA, err := json.Marshal(docA)
dataA, err := json.Marshal(mt)
require.NoError(t, err)
require.JSONEq(t, string(data), string(mediaTypeJSON))
require.JSONEq(t, string(data), string(dataA))
13 changes: 13 additions & 0 deletions openapi3/openapi3.go
Original file line number Diff line number Diff line change
@@ -19,6 +19,8 @@ type T struct {
Servers Servers `json:"servers,omitempty" yaml:"servers,omitempty"`
Tags Tags `json:"tags,omitempty" yaml:"tags,omitempty"`
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`

refd, refdAsReq, refdAsRep schemaLoader
}

func (doc *T) MarshalJSON() ([]byte, error) {
@@ -29,6 +31,17 @@ func (doc *T) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, doc)
}

// CompileSchemas needs to be called before any use of VisitJSON*()
func (doc *T) CompileSchemas() error {
if err := doc.compileSchemas(newSchemaValidationSettings(VisitAsRequest())); err != nil {
return err
}
if err := doc.compileSchemas(newSchemaValidationSettings(VisitAsResponse())); err != nil {
return err
}
return doc.compileSchemas(newSchemaValidationSettings())
}

func (doc *T) AddOperation(path string, method string, operation *Operation) {
paths := doc.Paths
if paths == nil {
11 changes: 11 additions & 0 deletions openapi3/openapi3_test.go
Original file line number Diff line number Diff line change
@@ -35,8 +35,12 @@ func TestRefsJSON(t *testing.T) {
t.Log("Validate *T")
err = docA.Validate(loader.Context)
require.NoError(t, err)
err = docA.CompileSchemas()
require.NoError(t, err)
err = docB.Validate(loader.Context)
require.NoError(t, err)
err = docB.CompileSchemas()
require.NoError(t, err)

t.Log("Ensure representations match")
dataA, err := json.Marshal(docA)
@@ -73,8 +77,12 @@ func TestRefsYAML(t *testing.T) {
t.Log("Validate *T")
err = docA.Validate(loader.Context)
require.NoError(t, err)
err = docA.CompileSchemas()
require.NoError(t, err)
err = docB.Validate(loader.Context)
require.NoError(t, err)
err = docB.CompileSchemas()
require.NoError(t, err)

t.Log("Ensure representations match")
dataA, err := yaml.Marshal(docA)
@@ -416,6 +424,9 @@ components:
} else {
require.NoError(t, err)
}

err = doc.CompileSchemas()
require.NoError(t, err)
})
}
}
2 changes: 2 additions & 0 deletions openapi3/parameter_issue223_test.go
Original file line number Diff line number Diff line change
@@ -113,4 +113,6 @@ components:
require.NoError(t, err)
err = doc.Validate(context.Background())
require.EqualError(t, err, `invalid paths: operation GET /pets/{petId} must define exactly all path parameters (missing: [petId])`)
err = doc.CompileSchemas()
require.NoError(t, err)
}
2 changes: 2 additions & 0 deletions openapi3/paths_test.go
Original file line number Diff line number Diff line change
@@ -25,4 +25,6 @@ func TestPathValidate(t *testing.T) {
require.NoError(t, err)
err = doc.Paths.Validate(context.Background())
require.NoError(t, err)
err = doc.CompileSchemas()
require.NoError(t, err)
}
2 changes: 2 additions & 0 deletions openapi3/response_issue224_test.go
Original file line number Diff line number Diff line change
@@ -458,4 +458,6 @@ func TestEmptyResponsesAreInvalid(t *testing.T) {
require.Equal(t, doc.ExternalDocs.Description, "See AsyncAPI example")
err = doc.Validate(context.Background())
require.EqualError(t, err, `invalid paths: the responses object MUST contain at least one response code`)
err = doc.CompileSchemas()
require.NoError(t, err)
}
6 changes: 6 additions & 0 deletions openapi3/schema.go
Original file line number Diff line number Diff line change
@@ -125,6 +125,12 @@ type Schema struct {

var _ jsonpointer.JSONPointable = (*Schema)(nil)

// VisitData validates given data against schema, using components from doc if given.
// It will use #/components/schemas if given doc is non-nil and doc.CompileSchemas() was called.
func (schema *Schema) VisitData(doc *T, data interface{}, opts ...SchemaValidationOption) (err error) {
return schema.visitData(doc, data, opts...)
}

func NewSchema() *Schema {
return &Schema{}
}
Loading