Skip to content

Commit

Permalink
Added MarshalJSON to high level schema.
Browse files Browse the repository at this point in the history
When building the doctor and rending APIs, I realized that schemas were not being serialized properly when rendering JSON output, this change fixes that.
  • Loading branch information
daveshanley committed May 11, 2024
1 parent 9eec2a4 commit 0d9b190
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
46 changes: 46 additions & 0 deletions datamodel/high/base/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package base

import (
"encoding/json"
"github.com/pb33f/libopenapi/datamodel/high"
lowmodel "github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
Expand Down Expand Up @@ -492,6 +493,29 @@ func (s *Schema) MarshalYAML() (interface{}, error) {
return nb.Render(), nil
}

// MarshalJSON will create a ready to render JSON representation of the Schema object.
func (s *Schema) MarshalJSON() ([]byte, error) {
nb := high.NewNodeBuilder(s, s.low)

// determine index version
idx := s.GoLow().Index
if idx != nil {
if idx.GetConfig().SpecInfo != nil {
nb.Version = idx.GetConfig().SpecInfo.VersionNumeric
}
}
// render node
node := nb.Render()
var renderedJSON map[string]interface{}

// marshal into struct
_ = node.Decode(&renderedJSON)

// return JSON bytes
return json.Marshal(renderedJSON)
}

// MarshalYAMLInline will render out the Schema pointer as YAML, and all refs will be inlined fully
func (s *Schema) MarshalYAMLInline() (interface{}, error) {
nb := high.NewNodeBuilder(s, s.low)
nb.Resolve = true
Expand All @@ -504,3 +528,25 @@ func (s *Schema) MarshalYAMLInline() (interface{}, error) {
}
return nb.Render(), nil
}

// MarshalJSONInline will render out the Schema pointer as JSON, and all refs will be inlined fully
func (s *Schema) MarshalJSONInline() ([]byte, error) {
nb := high.NewNodeBuilder(s, s.low)
nb.Resolve = true
// determine index version
idx := s.GoLow().Index
if idx != nil {
if idx.GetConfig().SpecInfo != nil {
nb.Version = idx.GetConfig().SpecInfo.VersionNumeric
}
}
// render node
node := nb.Render()
var renderedJSON map[string]interface{}

// marshal into struct
_ = node.Decode(&renderedJSON)

// return JSON bytes
return json.Marshal(renderedJSON)
}
76 changes: 76 additions & 0 deletions datamodel/high/base/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -844,6 +844,82 @@ allOf:
assert.Equal(t, testSpec, string(schemaBytes))
}

func TestNewSchemaProxy_RenderSchema_JSON(t *testing.T) {
testSpec := `type: object
description: something object
`

var compNode yaml.Node
_ = yaml.Unmarshal([]byte(testSpec), &compNode)

sp := new(lowbase.SchemaProxy)

// add a config
idxConfig := index.CreateOpenAPIIndexConfig()
idxConfig.SpecInfo = &datamodel.SpecInfo{
VersionNumeric: 3,
}
idx := index.NewSpecIndexWithConfig(nil, idxConfig)

err := sp.Build(context.Background(), nil, compNode.Content[0], idx)
assert.NoError(t, err)

lowproxy := low.NodeReference[*lowbase.SchemaProxy]{
Value: sp,
ValueNode: compNode.Content[0],
}

schemaProxy := NewSchemaProxy(&lowproxy)
compiled := schemaProxy.Schema()

assert.Equal(t, schemaProxy, compiled.ParentProxy)

assert.NotNil(t, compiled)
assert.Nil(t, schemaProxy.GetBuildError())

// now render it out, it should be identical, but in JSON
schemaBytes, _ := compiled.MarshalJSON()
assert.Equal(t, `{"description":"something object","type":"object"}`, string(schemaBytes))
}

func TestNewSchemaProxy_RenderSchema_JSONInline(t *testing.T) {
testSpec := `type: object
description: something object
`

var compNode yaml.Node
_ = yaml.Unmarshal([]byte(testSpec), &compNode)

sp := new(lowbase.SchemaProxy)

// add a config
idxConfig := index.CreateOpenAPIIndexConfig()
idxConfig.SpecInfo = &datamodel.SpecInfo{
VersionNumeric: 3,
}
idx := index.NewSpecIndexWithConfig(nil, idxConfig)

err := sp.Build(context.Background(), nil, compNode.Content[0], idx)
assert.NoError(t, err)

lowproxy := low.NodeReference[*lowbase.SchemaProxy]{
Value: sp,
ValueNode: compNode.Content[0],
}

schemaProxy := NewSchemaProxy(&lowproxy)
compiled := schemaProxy.Schema()

assert.Equal(t, schemaProxy, compiled.ParentProxy)

assert.NotNil(t, compiled)
assert.Nil(t, schemaProxy.GetBuildError())

// now render it out, it should be identical, but in JSON
schemaBytes, _ := compiled.MarshalJSONInline()
assert.Equal(t, `{"description":"something object","type":"object"}`, string(schemaBytes))
}

func TestNewSchemaProxy_RenderSchemaWithMultipleObjectTypes(t *testing.T) {
testSpec := `type: object
description: something object
Expand Down

0 comments on commit 0d9b190

Please sign in to comment.