Skip to content

Commit

Permalink
Add examples field tag, allow array item example, update docs (#50)
Browse files Browse the repository at this point in the history
  • Loading branch information
vearutop authored Aug 26, 2022
1 parent 1645be0 commit aef653c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 16 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ These tags can be used:
* [`title`](https://json-schema.org/draft-04/json-schema-validation.html#rfc.section.6.1), string
* [`description`](https://json-schema.org/draft-04/json-schema-validation.html#rfc.section.6.1), string
* [`default`](https://json-schema.org/draft-04/json-schema-validation.html#rfc.section.6.2), can be scalar or JSON value
* [`example`](https://json-schema.org/draft/2020-12/json-schema-validation.html#name-examples), a scalar value that matches type of parent property, for an array it is applied to items
* [`examples`](https://json-schema.org/draft/2020-12/json-schema-validation.html#name-examples), a JSON array value
* [`const`](https://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.6.1.3), can be scalar or JSON value
* [`pattern`](https://json-schema.org/draft-04/json-schema-validation.html#rfc.section.5.2.3), string
* [`format`](https://json-schema.org/draft-04/json-schema-validation.html#rfc.section.7), string
Expand Down
49 changes: 33 additions & 16 deletions reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ func (r *Reflector) walkProperties(v reflect.Value, parent *Schema, rc *ReflectC
}

if !rc.SkipNonConstraints {
if err := reflectExample(&propertySchema, field); err != nil {
if err := reflectExamples(&propertySchema, field); err != nil {
return err
}
}
Expand Down Expand Up @@ -941,44 +941,59 @@ func checkNullability(propertySchema *Schema, rc *ReflectContext, ft reflect.Typ
}
}

func reflectExample(propertySchema *Schema, field reflect.StructField) error {
var val interface{}
func reflectExamples(propertySchema *Schema, field reflect.StructField) error {
if err := reflectExample(propertySchema, field); err != nil {
return err
}

if propertySchema.Type == nil || propertySchema.Type.SimpleTypes == nil {
value, ok := field.Tag.Lookup("examples")
if !ok {
return nil
}

t := *propertySchema.Type.SimpleTypes
switch t {
case String:
var val []interface{}
if err := json.Unmarshal([]byte(value), &val); err != nil {
return fmt.Errorf("failed to parse examples in field %s: %w", field.Name, err)
}

propertySchema.Examples = append(propertySchema.Examples, val...)

return nil
}

func reflectExample(propertySchema *Schema, field reflect.StructField) error {
var val interface{}

switch {
case propertySchema.HasType(String):
var example *string

refl.ReadStringPtrTag(field.Tag, "example", &example)

if example != nil {
val = *example
}
case Integer:
var example *int64
case propertySchema.HasType(Number) && val == nil:
var example *float64

if err := refl.ReadIntPtrTag(field.Tag, "example", &example); err != nil {
if err := refl.ReadFloatPtrTag(field.Tag, "example", &example); err != nil {
return err
}

if example != nil {
val = *example
}
case Number:
var example *float64
case propertySchema.HasType(Integer) && val == nil:
var example *int64

if err := refl.ReadFloatPtrTag(field.Tag, "example", &example); err != nil {
if err := refl.ReadIntPtrTag(field.Tag, "example", &example); err != nil {
return err
}

if example != nil {
val = *example
}
case Boolean:
case propertySchema.HasType(Boolean) && val == nil:
var example *bool

if err := refl.ReadBoolPtrTag(field.Tag, "example", &example); err != nil {
Expand All @@ -988,12 +1003,14 @@ func reflectExample(propertySchema *Schema, field reflect.StructField) error {
if example != nil {
val = *example
}
case Array, Null, Object:
case propertySchema.HasType(Array) && val == nil:
return reflectExample(propertySchema.Items.SchemaOrBool.TypeObject, field)
default:
return nil
}

if val != nil {
propertySchema.WithExamples(val)
propertySchema.Examples = append(propertySchema.Examples, val)
}

return nil
Expand Down
24 changes: 24 additions & 0 deletions reflect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1275,3 +1275,27 @@ func TestReflector_Reflect_skipNonConstraints(t *testing.T) {
}
}`), s)
}

func TestReflector_Reflect_examples(t *testing.T) {
type WantExample struct {
A string `json:"a" example:"example of a"`
B []string `json:"b" example:"example of b"`
C int `json:"c" examples:"[\"foo\", 2, 3]" example:"123"`
}

reflector := jsonschema.Reflector{}
schema, err := reflector.Reflect(WantExample{})
require.NoError(t, err)

assertjson.EqualMarshal(t, []byte(`{
"properties":{
"a":{"examples":["example of a"],"type":"string"},
"b":{
"items":{"examples":["example of b"],"type":"string"},
"type":["array","null"]
},
"c":{"examples":[123,"foo",2,3],"type":"integer"}
},
"type":"object"
}`), schema)
}

0 comments on commit aef653c

Please sign in to comment.