@@ -6,49 +6,161 @@ import (
66 "github.com/getkin/kin-openapi/openapi3"
77)
88
9- // getTypedExampleFromSchema will return an example from a given schema
10- func getTypedExampleFromSchema (schema * openapi3.Schema ) (interface {}, error ) {
9+ func getSchemaExample (schema * openapi3.Schema ) (interface {}, bool ) {
1110 if schema .Example != nil {
12- return schema .Example , nil
11+ return schema .Example , true
1312 }
1413
15- if schema .Type == "number" {
16- return 0 , nil
14+ if schema .Default != nil {
15+ return schema . Default , true
1716 }
18- if schema .Type == "integer" {
19- return 0 , nil
17+
18+ if schema .Enum != nil && len (schema .Enum ) > 0 {
19+ return schema .Enum [0 ], true
2020 }
21- if schema .Type == "boolean" {
22- return true , nil
21+
22+ return nil , false
23+ }
24+
25+ // stringFormatExample returns an example string based on the given format.
26+ // http://json-schema.org/latest/json-schema-validation.html#rfc.section.7.3
27+ func stringFormatExample (format string ) string {
28+ switch format {
29+ case "date" :
30+ // https://tools.ietf.org/html/rfc3339
31+ return "2018-07-23"
32+ case "date-time" :
33+ // This is the date/time of API Sprout's first commit! :-)
34+ return "2018-07-23T22:58:00-07:00"
35+ case "time" :
36+ return "22:58:00-07:00"
37+ case "email" :
38+ 39+ case "hostname" :
40+ // https://tools.ietf.org/html/rfc2606#page-2
41+ return "example.com"
42+ case "ipv4" :
43+ // https://tools.ietf.org/html/rfc5737
44+ return "198.51.100.0"
45+ case "ipv6" :
46+ // https://tools.ietf.org/html/rfc3849
47+ return "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
48+ case "uri" :
49+ return "https://tools.ietf.org/html/rfc3986"
50+ case "uri-template" :
51+ // https://tools.ietf.org/html/rfc6570
52+ return "http://example.com/dictionary/{term:1}/{term}"
53+ case "json-pointer" :
54+ // https://tools.ietf.org/html/rfc6901
55+ return "#/components/parameters/term"
56+ case "regex" :
57+ // https://stackoverflow.com/q/3296050/164268
58+ return "/^1?$|^(11+?)\\ 1+$/"
59+ case "uuid" :
60+ // https://www.ietf.org/rfc/rfc4122.txt
61+ return "f81d4fae-7dec-11d0-a765-00a0c91e6bf6"
62+ case "password" :
63+ return "********"
2364 }
24- if schema .Type == "string" {
25- return "string" , nil
65+
66+ return ""
67+ }
68+
69+ // OpenAPIExample creates an example structure from an OpenAPI 3 schema
70+ // object, which is an extended subset of JSON Schema.
71+ // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#schemaObject
72+ func OpenAPIExample (schema * openapi3.Schema ) (interface {}, error ) {
73+ if ex , ok := getSchemaExample (schema ); ok {
74+ return ex , nil
2675 }
27- if schema .Type == "array" {
76+
77+ switch {
78+ case schema .Type == "boolean" :
79+ return true , nil
80+ case schema .Type == "number" , schema .Type == "integer" :
81+ value := 0.0
82+
83+ if schema .Min != nil && * schema .Min > value {
84+ value = * schema .Min
85+ if schema .ExclusiveMin {
86+ if schema .Max != nil {
87+ // Make the value half way.
88+ value = (* schema .Min + * schema .Max ) / 2.0
89+ } else {
90+ value ++
91+ }
92+ }
93+ }
94+
95+ if schema .Max != nil && * schema .Max < value {
96+ value = * schema .Max
97+ if schema .ExclusiveMax {
98+ if schema .Min != nil {
99+ // Make the value half way.
100+ value = (* schema .Min + * schema .Max ) / 2.0
101+ } else {
102+ value --
103+ }
104+ }
105+ }
106+
107+ if schema .MultipleOf != nil && int (value )% int (* schema .MultipleOf ) != 0 {
108+ value += float64 (int (* schema .MultipleOf ) - (int (value ) % int (* schema .MultipleOf )))
109+ }
110+
111+ if schema .Type == "integer" {
112+ return int (value ), nil
113+ }
114+
115+ return value , nil
116+ case schema .Type == "string" :
117+ if ex := stringFormatExample (schema .Format ); ex != "" {
118+ return ex , nil
119+ }
120+
121+ example := "string"
122+
123+ for schema .MinLength > uint64 (len (example )) {
124+ example += example
125+ }
126+
127+ if schema .MaxLength != nil && * schema .MaxLength < uint64 (len (example )) {
128+ example = example [:* schema .MaxLength ]
129+ }
130+
131+ return example , nil
132+ case schema .Type == "array" , schema .Items != nil :
28133 example := []interface {}{}
134+
29135 if schema .Items != nil && schema .Items .Value != nil {
30- ex , err := getTypedExampleFromSchema (schema .Items .Value )
136+ ex , err := OpenAPIExample (schema .Items .Value )
31137 if err != nil {
32138 return nil , fmt .Errorf ("can't get example for array item" )
33139 }
140+
34141 example = append (example , ex )
142+
143+ for uint64 (len (example )) < schema .MinItems {
144+ example = append (example , ex )
145+ }
35146 }
36- return example , nil
37- }
38147
39- if schema .Type == "object" || len (schema .Properties ) > 0 {
148+ return example , nil
149+ case schema .Type == "object" , len (schema .Properties ) > 0 :
40150 example := map [string ]interface {}{}
151+
41152 for k , v := range schema .Properties {
42- ex , err := getTypedExampleFromSchema (v .Value )
153+ ex , err := OpenAPIExample (v .Value )
43154 if err != nil {
44155 return nil , fmt .Errorf ("can't get example for '%s'" , k )
45156 }
157+
46158 example [k ] = ex
47159 }
48160
49161 if schema .AdditionalProperties != nil && schema .AdditionalProperties .Value != nil {
50162 addl := schema .AdditionalProperties .Value
51- ex , err := getTypedExampleFromSchema (addl )
163+ ex , err := OpenAPIExample (addl )
52164 if err != nil {
53165 return nil , fmt .Errorf ("can't get example for additional properties" )
54166 }
0 commit comments