@@ -92,26 +92,76 @@ func excludeFromMode(mode Mode, schema *openapi3.Schema) bool {
9292	return  false 
9393}
9494
95- // OpenAPIExample creates an example structure from an OpenAPI 3 schema 
96- // object, which is an extended subset of JSON Schema. 
97- // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#schemaObject 
98- func  OpenAPIExample (mode  Mode , schema  * openapi3.Schema ) (interface {}, error ) {
95+ // isRequired checks whether a key is actually required. 
96+ func  isRequired (schema  * openapi3.Schema , key  string ) bool  {
97+ 	for  _ , req  :=  range  schema .Required  {
98+ 		if  req  ==  key  {
99+ 			return  true 
100+ 		}
101+ 	}
102+ 
103+ 	return  false 
104+ }
105+ 
106+ type  cachedSchema  struct  {
107+ 	pending  bool 
108+ 	out      interface {}
109+ }
110+ 
111+ func  openAPIExample (mode  Mode , schema  * openapi3.Schema , cache  map [* openapi3.Schema ]* cachedSchema ) (out  interface {}, err  error ) {
99112	if  ex , ok  :=  getSchemaExample (schema ); ok  {
100113		return  ex , nil 
101114	}
102115
116+ 	cached , ok  :=  cache [schema ]
117+ 	if  ! ok  {
118+ 		cached  =  & cachedSchema {
119+ 			pending : true ,
120+ 		}
121+ 		cache [schema ] =  cached 
122+ 	} else  if  cached .pending  {
123+ 		return  nil , ErrRecursive 
124+ 	} else  {
125+ 		return  cached .out , nil 
126+ 	}
127+ 
128+ 	defer  func () {
129+ 		cached .pending  =  false 
130+ 		cached .out  =  out 
131+ 	}()
132+ 
103133	// Handle combining keywords 
104134	if  len (schema .OneOf ) >  0  {
105- 		return  OpenAPIExample (mode , schema .OneOf [0 ].Value )
135+ 		var  ex  interface {}
136+ 		var  err  error 
137+ 
138+ 		for  _ , candidate  :=  range  schema .OneOf  {
139+ 			ex , err  =  openAPIExample (mode , candidate .Value , cache )
140+ 			if  err  ==  nil  {
141+ 				break 
142+ 			}
143+ 		}
144+ 
145+ 		return  ex , err 
106146	}
107147	if  len (schema .AnyOf ) >  0  {
108- 		return  OpenAPIExample (mode , schema .AnyOf [0 ].Value )
148+ 		var  ex  interface {}
149+ 		var  err  error 
150+ 
151+ 		for  _ , candidate  :=  range  schema .AnyOf  {
152+ 			ex , err  =  openAPIExample (mode , candidate .Value , cache )
153+ 			if  err  ==  nil  {
154+ 				break 
155+ 			}
156+ 		}
157+ 
158+ 		return  ex , err 
109159	}
110160	if  len (schema .AllOf ) >  0  {
111161		example  :=  map [string ]interface {}{}
112162
113163		for  _ , allOf  :=  range  schema .AllOf  {
114- 			candidate , err  :=  OpenAPIExample (mode , allOf .Value )
164+ 			candidate , err  :=  openAPIExample (mode , allOf .Value ,  cache )
115165			if  err  !=  nil  {
116166				return  nil , err 
117167			}
@@ -188,9 +238,9 @@ func OpenAPIExample(mode Mode, schema *openapi3.Schema) (interface{}, error) {
188238		example  :=  []interface {}{}
189239
190240		if  schema .Items  !=  nil  &&  schema .Items .Value  !=  nil  {
191- 			ex , err  :=  OpenAPIExample (mode , schema .Items .Value )
241+ 			ex , err  :=  openAPIExample (mode , schema .Items .Value ,  cache )
192242			if  err  !=  nil  {
193- 				return  nil , fmt .Errorf ("can't get example for array item"  )
243+ 				return  nil , fmt .Errorf ("can't get example for array item: %+v"  ,  err )
194244			}
195245
196246			example  =  append (example , ex )
@@ -209,24 +259,30 @@ func OpenAPIExample(mode Mode, schema *openapi3.Schema) (interface{}, error) {
209259				continue 
210260			}
211261
212- 			ex , err  :=  OpenAPIExample (mode , v .Value )
213- 			if  err  !=  nil  {
214- 				return  nil , fmt .Errorf ("can't get example for '%s'" , k )
262+ 			ex , err  :=  openAPIExample (mode , v .Value , cache )
263+ 			if  err  ==  ErrRecursive  {
264+ 				if  isRequired (schema , k ) {
265+ 					return  nil , fmt .Errorf ("can't get example for '%s': %+v" , k , err )
266+ 				}
267+ 			} else  if  err  !=  nil  {
268+ 				return  nil , fmt .Errorf ("can't get example for '%s': %+v" , k , err )
269+ 			} else  {
270+ 				example [k ] =  ex 
215271			}
216- 
217- 			example [k ] =  ex 
218272		}
219273
220274		if  schema .AdditionalProperties  !=  nil  &&  schema .AdditionalProperties .Value  !=  nil  {
221275			addl  :=  schema .AdditionalProperties .Value 
222276
223277			if  ! excludeFromMode (mode , addl ) {
224- 				ex , err  :=  OpenAPIExample (mode , addl )
225- 				if  err  !=  nil  {
226- 					return  nil , fmt .Errorf ("can't get example for additional properties" )
278+ 				ex , err  :=  openAPIExample (mode , addl , cache )
279+ 				if  err  ==  ErrRecursive  {
280+ 					// We just won't add this if it's recursive. 
281+ 				} else  if  err  !=  nil  {
282+ 					return  nil , fmt .Errorf ("can't get example for additional properties: %+v" , err )
283+ 				} else  {
284+ 					example ["additionalPropertyName" ] =  ex 
227285				}
228- 
229- 				example ["additionalPropertyName" ] =  ex 
230286			}
231287		}
232288
@@ -235,3 +291,10 @@ func OpenAPIExample(mode Mode, schema *openapi3.Schema) (interface{}, error) {
235291
236292	return  nil , ErrNoExample 
237293}
294+ 
295+ // OpenAPIExample creates an example structure from an OpenAPI 3 schema 
296+ // object, which is an extended subset of JSON Schema. 
297+ // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#schemaObject 
298+ func  OpenAPIExample (mode  Mode , schema  * openapi3.Schema ) (interface {}, error ) {
299+ 	return  openAPIExample (mode , schema , make (map [* openapi3.Schema ]* cachedSchema ))
300+ }
0 commit comments