1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package spec
16
17 import (
18 "encoding/json"
19 "fmt"
20 "strings"
21
22 "github.com/go-openapi/jsonpointer"
23 "github.com/go-openapi/swag"
24 )
25
26
27 func BooleanProperty() *Schema {
28 return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}}
29 }
30
31
32 func BoolProperty() *Schema { return BooleanProperty() }
33
34
35 func StringProperty() *Schema {
36 return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
37 }
38
39
40 func CharProperty() *Schema {
41 return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
42 }
43
44
45 func Float64Property() *Schema {
46 return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}}
47 }
48
49
50 func Float32Property() *Schema {
51 return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}}
52 }
53
54
55 func Int8Property() *Schema {
56 return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}}
57 }
58
59
60 func Int16Property() *Schema {
61 return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}}
62 }
63
64
65 func Int32Property() *Schema {
66 return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}}
67 }
68
69
70 func Int64Property() *Schema {
71 return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}}
72 }
73
74
75 func StrFmtProperty(format string) *Schema {
76 return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}}
77 }
78
79
80 func DateProperty() *Schema {
81 return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}}
82 }
83
84
85 func DateTimeProperty() *Schema {
86 return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}}
87 }
88
89
90 func MapProperty(property *Schema) *Schema {
91 return &Schema{SchemaProps: SchemaProps{Type: []string{"object"},
92 AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}}
93 }
94
95
96 func RefProperty(name string) *Schema {
97 return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
98 }
99
100
101 func RefSchema(name string) *Schema {
102 return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
103 }
104
105
106 func ArrayProperty(items *Schema) *Schema {
107 if items == nil {
108 return &Schema{SchemaProps: SchemaProps{Type: []string{"array"}}}
109 }
110 return &Schema{SchemaProps: SchemaProps{Items: &SchemaOrArray{Schema: items}, Type: []string{"array"}}}
111 }
112
113
114 func ComposedSchema(schemas ...Schema) *Schema {
115 s := new(Schema)
116 s.AllOf = schemas
117 return s
118 }
119
120
121 type SchemaURL string
122
123
124 func (r SchemaURL) MarshalJSON() ([]byte, error) {
125 if r == "" {
126 return []byte("{}"), nil
127 }
128 v := map[string]interface{}{"$schema": string(r)}
129 return json.Marshal(v)
130 }
131
132
133 func (r *SchemaURL) UnmarshalJSON(data []byte) error {
134 var v map[string]interface{}
135 if err := json.Unmarshal(data, &v); err != nil {
136 return err
137 }
138 return r.fromMap(v)
139 }
140
141 func (r *SchemaURL) fromMap(v map[string]interface{}) error {
142 if v == nil {
143 return nil
144 }
145 if vv, ok := v["$schema"]; ok {
146 if str, ok := vv.(string); ok {
147 u, err := parseURL(str)
148 if err != nil {
149 return err
150 }
151
152 *r = SchemaURL(u.String())
153 }
154 }
155 return nil
156 }
157
158
159 type SchemaProps struct {
160 ID string `json:"id,omitempty"`
161 Ref Ref `json:"-"`
162 Schema SchemaURL `json:"-"`
163 Description string `json:"description,omitempty"`
164 Type StringOrArray `json:"type,omitempty"`
165 Nullable bool `json:"nullable,omitempty"`
166 Format string `json:"format,omitempty"`
167 Title string `json:"title,omitempty"`
168 Default interface{} `json:"default,omitempty"`
169 Maximum *float64 `json:"maximum,omitempty"`
170 ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"`
171 Minimum *float64 `json:"minimum,omitempty"`
172 ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"`
173 MaxLength *int64 `json:"maxLength,omitempty"`
174 MinLength *int64 `json:"minLength,omitempty"`
175 Pattern string `json:"pattern,omitempty"`
176 MaxItems *int64 `json:"maxItems,omitempty"`
177 MinItems *int64 `json:"minItems,omitempty"`
178 UniqueItems bool `json:"uniqueItems,omitempty"`
179 MultipleOf *float64 `json:"multipleOf,omitempty"`
180 Enum []interface{} `json:"enum,omitempty"`
181 MaxProperties *int64 `json:"maxProperties,omitempty"`
182 MinProperties *int64 `json:"minProperties,omitempty"`
183 Required []string `json:"required,omitempty"`
184 Items *SchemaOrArray `json:"items,omitempty"`
185 AllOf []Schema `json:"allOf,omitempty"`
186 OneOf []Schema `json:"oneOf,omitempty"`
187 AnyOf []Schema `json:"anyOf,omitempty"`
188 Not *Schema `json:"not,omitempty"`
189 Properties SchemaProperties `json:"properties,omitempty"`
190 AdditionalProperties *SchemaOrBool `json:"additionalProperties,omitempty"`
191 PatternProperties SchemaProperties `json:"patternProperties,omitempty"`
192 Dependencies Dependencies `json:"dependencies,omitempty"`
193 AdditionalItems *SchemaOrBool `json:"additionalItems,omitempty"`
194 Definitions Definitions `json:"definitions,omitempty"`
195 }
196
197
198 type SwaggerSchemaProps struct {
199 Discriminator string `json:"discriminator,omitempty"`
200 ReadOnly bool `json:"readOnly,omitempty"`
201 XML *XMLObject `json:"xml,omitempty"`
202 ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"`
203 Example interface{} `json:"example,omitempty"`
204 }
205
206
207
208
209
210
211
212
213 type Schema struct {
214 VendorExtensible
215 SchemaProps
216 SwaggerSchemaProps
217 ExtraProps map[string]interface{} `json:"-"`
218 }
219
220
221 func (s Schema) JSONLookup(token string) (interface{}, error) {
222 if ex, ok := s.Extensions[token]; ok {
223 return &ex, nil
224 }
225
226 if ex, ok := s.ExtraProps[token]; ok {
227 return &ex, nil
228 }
229
230 r, _, err := jsonpointer.GetForToken(s.SchemaProps, token)
231 if r != nil || (err != nil && !strings.HasPrefix(err.Error(), "object has no field")) {
232 return r, err
233 }
234 r, _, err = jsonpointer.GetForToken(s.SwaggerSchemaProps, token)
235 return r, err
236 }
237
238
239 func (s *Schema) WithID(id string) *Schema {
240 s.ID = id
241 return s
242 }
243
244
245 func (s *Schema) WithTitle(title string) *Schema {
246 s.Title = title
247 return s
248 }
249
250
251 func (s *Schema) WithDescription(description string) *Schema {
252 s.Description = description
253 return s
254 }
255
256
257 func (s *Schema) WithProperties(schemas map[string]Schema) *Schema {
258 s.Properties = schemas
259 return s
260 }
261
262
263 func (s *Schema) SetProperty(name string, schema Schema) *Schema {
264 if s.Properties == nil {
265 s.Properties = make(map[string]Schema)
266 }
267 s.Properties[name] = schema
268 return s
269 }
270
271
272 func (s *Schema) WithAllOf(schemas ...Schema) *Schema {
273 s.AllOf = schemas
274 return s
275 }
276
277
278 func (s *Schema) WithMaxProperties(max int64) *Schema {
279 s.MaxProperties = &max
280 return s
281 }
282
283
284 func (s *Schema) WithMinProperties(min int64) *Schema {
285 s.MinProperties = &min
286 return s
287 }
288
289
290 func (s *Schema) Typed(tpe, format string) *Schema {
291 s.Type = []string{tpe}
292 s.Format = format
293 return s
294 }
295
296
297 func (s *Schema) AddType(tpe, format string) *Schema {
298 s.Type = append(s.Type, tpe)
299 if format != "" {
300 s.Format = format
301 }
302 return s
303 }
304
305
306 func (s *Schema) AsNullable() *Schema {
307 s.Nullable = true
308 return s
309 }
310
311
312 func (s *Schema) CollectionOf(items Schema) *Schema {
313 s.Type = []string{jsonArray}
314 s.Items = &SchemaOrArray{Schema: &items}
315 return s
316 }
317
318
319 func (s *Schema) WithDefault(defaultValue interface{}) *Schema {
320 s.Default = defaultValue
321 return s
322 }
323
324
325 func (s *Schema) WithRequired(items ...string) *Schema {
326 s.Required = items
327 return s
328 }
329
330
331 func (s *Schema) AddRequired(items ...string) *Schema {
332 s.Required = append(s.Required, items...)
333 return s
334 }
335
336
337 func (s *Schema) WithMaxLength(max int64) *Schema {
338 s.MaxLength = &max
339 return s
340 }
341
342
343 func (s *Schema) WithMinLength(min int64) *Schema {
344 s.MinLength = &min
345 return s
346 }
347
348
349 func (s *Schema) WithPattern(pattern string) *Schema {
350 s.Pattern = pattern
351 return s
352 }
353
354
355 func (s *Schema) WithMultipleOf(number float64) *Schema {
356 s.MultipleOf = &number
357 return s
358 }
359
360
361 func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema {
362 s.Maximum = &max
363 s.ExclusiveMaximum = exclusive
364 return s
365 }
366
367
368 func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema {
369 s.Minimum = &min
370 s.ExclusiveMinimum = exclusive
371 return s
372 }
373
374
375 func (s *Schema) WithEnum(values ...interface{}) *Schema {
376 s.Enum = append([]interface{}{}, values...)
377 return s
378 }
379
380
381 func (s *Schema) WithMaxItems(size int64) *Schema {
382 s.MaxItems = &size
383 return s
384 }
385
386
387 func (s *Schema) WithMinItems(size int64) *Schema {
388 s.MinItems = &size
389 return s
390 }
391
392
393 func (s *Schema) UniqueValues() *Schema {
394 s.UniqueItems = true
395 return s
396 }
397
398
399 func (s *Schema) AllowDuplicates() *Schema {
400 s.UniqueItems = false
401 return s
402 }
403
404
405 func (s *Schema) AddToAllOf(schemas ...Schema) *Schema {
406 s.AllOf = append(s.AllOf, schemas...)
407 return s
408 }
409
410
411 func (s *Schema) WithDiscriminator(discriminator string) *Schema {
412 s.Discriminator = discriminator
413 return s
414 }
415
416
417 func (s *Schema) AsReadOnly() *Schema {
418 s.ReadOnly = true
419 return s
420 }
421
422
423 func (s *Schema) AsWritable() *Schema {
424 s.ReadOnly = false
425 return s
426 }
427
428
429 func (s *Schema) WithExample(example interface{}) *Schema {
430 s.Example = example
431 return s
432 }
433
434
435
436
437
438 func (s *Schema) WithExternalDocs(description, url string) *Schema {
439 if description == "" && url == "" {
440 s.ExternalDocs = nil
441 return s
442 }
443
444 if s.ExternalDocs == nil {
445 s.ExternalDocs = &ExternalDocumentation{}
446 }
447 s.ExternalDocs.Description = description
448 s.ExternalDocs.URL = url
449 return s
450 }
451
452
453 func (s *Schema) WithXMLName(name string) *Schema {
454 if s.XML == nil {
455 s.XML = new(XMLObject)
456 }
457 s.XML.Name = name
458 return s
459 }
460
461
462 func (s *Schema) WithXMLNamespace(namespace string) *Schema {
463 if s.XML == nil {
464 s.XML = new(XMLObject)
465 }
466 s.XML.Namespace = namespace
467 return s
468 }
469
470
471 func (s *Schema) WithXMLPrefix(prefix string) *Schema {
472 if s.XML == nil {
473 s.XML = new(XMLObject)
474 }
475 s.XML.Prefix = prefix
476 return s
477 }
478
479
480 func (s *Schema) AsXMLAttribute() *Schema {
481 if s.XML == nil {
482 s.XML = new(XMLObject)
483 }
484 s.XML.Attribute = true
485 return s
486 }
487
488
489 func (s *Schema) AsXMLElement() *Schema {
490 if s.XML == nil {
491 s.XML = new(XMLObject)
492 }
493 s.XML.Attribute = false
494 return s
495 }
496
497
498 func (s *Schema) AsWrappedXML() *Schema {
499 if s.XML == nil {
500 s.XML = new(XMLObject)
501 }
502 s.XML.Wrapped = true
503 return s
504 }
505
506
507 func (s *Schema) AsUnwrappedXML() *Schema {
508 if s.XML == nil {
509 s.XML = new(XMLObject)
510 }
511 s.XML.Wrapped = false
512 return s
513 }
514
515
516
517
518 func (s *Schema) SetValidations(val SchemaValidations) {
519 s.Maximum = val.Maximum
520 s.ExclusiveMaximum = val.ExclusiveMaximum
521 s.Minimum = val.Minimum
522 s.ExclusiveMinimum = val.ExclusiveMinimum
523 s.MaxLength = val.MaxLength
524 s.MinLength = val.MinLength
525 s.Pattern = val.Pattern
526 s.MaxItems = val.MaxItems
527 s.MinItems = val.MinItems
528 s.UniqueItems = val.UniqueItems
529 s.MultipleOf = val.MultipleOf
530 s.Enum = val.Enum
531 s.MinProperties = val.MinProperties
532 s.MaxProperties = val.MaxProperties
533 s.PatternProperties = val.PatternProperties
534 }
535
536
537 func (s *Schema) WithValidations(val SchemaValidations) *Schema {
538 s.SetValidations(val)
539 return s
540 }
541
542
543 func (s Schema) Validations() SchemaValidations {
544 return SchemaValidations{
545 CommonValidations: CommonValidations{
546 Maximum: s.Maximum,
547 ExclusiveMaximum: s.ExclusiveMaximum,
548 Minimum: s.Minimum,
549 ExclusiveMinimum: s.ExclusiveMinimum,
550 MaxLength: s.MaxLength,
551 MinLength: s.MinLength,
552 Pattern: s.Pattern,
553 MaxItems: s.MaxItems,
554 MinItems: s.MinItems,
555 UniqueItems: s.UniqueItems,
556 MultipleOf: s.MultipleOf,
557 Enum: s.Enum,
558 },
559 MinProperties: s.MinProperties,
560 MaxProperties: s.MaxProperties,
561 PatternProperties: s.PatternProperties,
562 }
563 }
564
565
566 func (s Schema) MarshalJSON() ([]byte, error) {
567 b1, err := json.Marshal(s.SchemaProps)
568 if err != nil {
569 return nil, fmt.Errorf("schema props %v", err)
570 }
571 b2, err := json.Marshal(s.VendorExtensible)
572 if err != nil {
573 return nil, fmt.Errorf("vendor props %v", err)
574 }
575 b3, err := s.Ref.MarshalJSON()
576 if err != nil {
577 return nil, fmt.Errorf("ref prop %v", err)
578 }
579 b4, err := s.Schema.MarshalJSON()
580 if err != nil {
581 return nil, fmt.Errorf("schema prop %v", err)
582 }
583 b5, err := json.Marshal(s.SwaggerSchemaProps)
584 if err != nil {
585 return nil, fmt.Errorf("common validations %v", err)
586 }
587 var b6 []byte
588 if s.ExtraProps != nil {
589 jj, err := json.Marshal(s.ExtraProps)
590 if err != nil {
591 return nil, fmt.Errorf("extra props %v", err)
592 }
593 b6 = jj
594 }
595 return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil
596 }
597
598
599 func (s *Schema) UnmarshalJSON(data []byte) error {
600 props := struct {
601 SchemaProps
602 SwaggerSchemaProps
603 }{}
604 if err := json.Unmarshal(data, &props); err != nil {
605 return err
606 }
607
608 sch := Schema{
609 SchemaProps: props.SchemaProps,
610 SwaggerSchemaProps: props.SwaggerSchemaProps,
611 }
612
613 var d map[string]interface{}
614 if err := json.Unmarshal(data, &d); err != nil {
615 return err
616 }
617
618 _ = sch.Ref.fromMap(d)
619 _ = sch.Schema.fromMap(d)
620
621 delete(d, "$ref")
622 delete(d, "$schema")
623 for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) {
624 delete(d, pn)
625 }
626
627 for k, vv := range d {
628 lk := strings.ToLower(k)
629 if strings.HasPrefix(lk, "x-") {
630 if sch.Extensions == nil {
631 sch.Extensions = map[string]interface{}{}
632 }
633 sch.Extensions[k] = vv
634 continue
635 }
636 if sch.ExtraProps == nil {
637 sch.ExtraProps = map[string]interface{}{}
638 }
639 sch.ExtraProps[k] = vv
640 }
641
642 *s = sch
643
644 return nil
645 }
646
View as plain text