Matthias Andreas Benkard | 832a54e | 2019-01-29 09:27:38 +0100 | [diff] [blame] | 1 | // Copyright 2015 go-swagger maintainers |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | package spec |
| 16 | |
| 17 | import ( |
| 18 | "encoding/json" |
| 19 | "fmt" |
| 20 | "net/url" |
| 21 | "strings" |
| 22 | |
| 23 | "github.com/go-openapi/jsonpointer" |
| 24 | "github.com/go-openapi/swag" |
| 25 | ) |
| 26 | |
| 27 | // BooleanProperty creates a boolean property |
| 28 | func BooleanProperty() *Schema { |
| 29 | return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}} |
| 30 | } |
| 31 | |
| 32 | // BoolProperty creates a boolean property |
| 33 | func BoolProperty() *Schema { return BooleanProperty() } |
| 34 | |
| 35 | // StringProperty creates a string property |
| 36 | func StringProperty() *Schema { |
| 37 | return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}} |
| 38 | } |
| 39 | |
| 40 | // CharProperty creates a string property |
| 41 | func CharProperty() *Schema { |
| 42 | return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}} |
| 43 | } |
| 44 | |
| 45 | // Float64Property creates a float64/double property |
| 46 | func Float64Property() *Schema { |
| 47 | return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}} |
| 48 | } |
| 49 | |
| 50 | // Float32Property creates a float32/float property |
| 51 | func Float32Property() *Schema { |
| 52 | return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}} |
| 53 | } |
| 54 | |
| 55 | // Int8Property creates an int8 property |
| 56 | func Int8Property() *Schema { |
| 57 | return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}} |
| 58 | } |
| 59 | |
| 60 | // Int16Property creates an int16 property |
| 61 | func Int16Property() *Schema { |
| 62 | return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}} |
| 63 | } |
| 64 | |
| 65 | // Int32Property creates an int32 property |
| 66 | func Int32Property() *Schema { |
| 67 | return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}} |
| 68 | } |
| 69 | |
| 70 | // Int64Property creates an int64 property |
| 71 | func Int64Property() *Schema { |
| 72 | return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}} |
| 73 | } |
| 74 | |
| 75 | // StrFmtProperty creates a property for the named string format |
| 76 | func StrFmtProperty(format string) *Schema { |
| 77 | return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}} |
| 78 | } |
| 79 | |
| 80 | // DateProperty creates a date property |
| 81 | func DateProperty() *Schema { |
| 82 | return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}} |
| 83 | } |
| 84 | |
| 85 | // DateTimeProperty creates a date time property |
| 86 | func DateTimeProperty() *Schema { |
| 87 | return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}} |
| 88 | } |
| 89 | |
| 90 | // MapProperty creates a map property |
| 91 | func MapProperty(property *Schema) *Schema { |
| 92 | return &Schema{SchemaProps: SchemaProps{Type: []string{"object"}, AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}} |
| 93 | } |
| 94 | |
| 95 | // RefProperty creates a ref property |
| 96 | func RefProperty(name string) *Schema { |
| 97 | return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}} |
| 98 | } |
| 99 | |
| 100 | // RefSchema creates a ref property |
| 101 | func RefSchema(name string) *Schema { |
| 102 | return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}} |
| 103 | } |
| 104 | |
| 105 | // ArrayProperty creates an array property |
| 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 | // ComposedSchema creates a schema with allOf |
| 114 | func ComposedSchema(schemas ...Schema) *Schema { |
| 115 | s := new(Schema) |
| 116 | s.AllOf = schemas |
| 117 | return s |
| 118 | } |
| 119 | |
| 120 | // SchemaURL represents a schema url |
| 121 | type SchemaURL string |
| 122 | |
| 123 | // MarshalJSON marshal this to JSON |
| 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 | // UnmarshalJSON unmarshal this from JSON |
| 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 := url.Parse(str) |
| 148 | if err != nil { |
| 149 | return err |
| 150 | } |
| 151 | |
| 152 | *r = SchemaURL(u.String()) |
| 153 | } |
| 154 | } |
| 155 | return nil |
| 156 | } |
| 157 | |
| 158 | // type ExtraSchemaProps map[string]interface{} |
| 159 | |
| 160 | // // JSONSchema represents a structure that is a json schema draft 04 |
| 161 | // type JSONSchema struct { |
| 162 | // SchemaProps |
| 163 | // ExtraSchemaProps |
| 164 | // } |
| 165 | |
| 166 | // // MarshalJSON marshal this to JSON |
| 167 | // func (s JSONSchema) MarshalJSON() ([]byte, error) { |
| 168 | // b1, err := json.Marshal(s.SchemaProps) |
| 169 | // if err != nil { |
| 170 | // return nil, err |
| 171 | // } |
| 172 | // b2, err := s.Ref.MarshalJSON() |
| 173 | // if err != nil { |
| 174 | // return nil, err |
| 175 | // } |
| 176 | // b3, err := s.Schema.MarshalJSON() |
| 177 | // if err != nil { |
| 178 | // return nil, err |
| 179 | // } |
| 180 | // b4, err := json.Marshal(s.ExtraSchemaProps) |
| 181 | // if err != nil { |
| 182 | // return nil, err |
| 183 | // } |
| 184 | // return swag.ConcatJSON(b1, b2, b3, b4), nil |
| 185 | // } |
| 186 | |
| 187 | // // UnmarshalJSON marshal this from JSON |
| 188 | // func (s *JSONSchema) UnmarshalJSON(data []byte) error { |
| 189 | // var sch JSONSchema |
| 190 | // if err := json.Unmarshal(data, &sch.SchemaProps); err != nil { |
| 191 | // return err |
| 192 | // } |
| 193 | // if err := json.Unmarshal(data, &sch.Ref); err != nil { |
| 194 | // return err |
| 195 | // } |
| 196 | // if err := json.Unmarshal(data, &sch.Schema); err != nil { |
| 197 | // return err |
| 198 | // } |
| 199 | // if err := json.Unmarshal(data, &sch.ExtraSchemaProps); err != nil { |
| 200 | // return err |
| 201 | // } |
| 202 | // *s = sch |
| 203 | // return nil |
| 204 | // } |
| 205 | |
| 206 | type SchemaProps struct { |
| 207 | ID string `json:"id,omitempty"` |
| 208 | Ref Ref `json:"-"` |
| 209 | Schema SchemaURL `json:"-"` |
| 210 | Description string `json:"description,omitempty"` |
| 211 | Type StringOrArray `json:"type,omitempty"` |
| 212 | Format string `json:"format,omitempty"` |
| 213 | Title string `json:"title,omitempty"` |
| 214 | Default interface{} `json:"default,omitempty"` |
| 215 | Maximum *float64 `json:"maximum,omitempty"` |
| 216 | ExclusiveMaximum bool `json:"exclusiveMaximum,omitempty"` |
| 217 | Minimum *float64 `json:"minimum,omitempty"` |
| 218 | ExclusiveMinimum bool `json:"exclusiveMinimum,omitempty"` |
| 219 | MaxLength *int64 `json:"maxLength,omitempty"` |
| 220 | MinLength *int64 `json:"minLength,omitempty"` |
| 221 | Pattern string `json:"pattern,omitempty"` |
| 222 | MaxItems *int64 `json:"maxItems,omitempty"` |
| 223 | MinItems *int64 `json:"minItems,omitempty"` |
| 224 | UniqueItems bool `json:"uniqueItems,omitempty"` |
| 225 | MultipleOf *float64 `json:"multipleOf,omitempty"` |
| 226 | Enum []interface{} `json:"enum,omitempty"` |
| 227 | MaxProperties *int64 `json:"maxProperties,omitempty"` |
| 228 | MinProperties *int64 `json:"minProperties,omitempty"` |
| 229 | Required []string `json:"required,omitempty"` |
| 230 | Items *SchemaOrArray `json:"items,omitempty"` |
| 231 | AllOf []Schema `json:"allOf,omitempty"` |
| 232 | OneOf []Schema `json:"oneOf,omitempty"` |
| 233 | AnyOf []Schema `json:"anyOf,omitempty"` |
| 234 | Not *Schema `json:"not,omitempty"` |
| 235 | Properties map[string]Schema `json:"properties,omitempty"` |
| 236 | AdditionalProperties *SchemaOrBool `json:"additionalProperties,omitempty"` |
| 237 | PatternProperties map[string]Schema `json:"patternProperties,omitempty"` |
| 238 | Dependencies Dependencies `json:"dependencies,omitempty"` |
| 239 | AdditionalItems *SchemaOrBool `json:"additionalItems,omitempty"` |
| 240 | Definitions Definitions `json:"definitions,omitempty"` |
| 241 | } |
| 242 | |
| 243 | type SwaggerSchemaProps struct { |
| 244 | Discriminator string `json:"discriminator,omitempty"` |
| 245 | ReadOnly bool `json:"readOnly,omitempty"` |
| 246 | XML *XMLObject `json:"xml,omitempty"` |
| 247 | ExternalDocs *ExternalDocumentation `json:"externalDocs,omitempty"` |
| 248 | Example interface{} `json:"example,omitempty"` |
| 249 | } |
| 250 | |
| 251 | // Schema the schema object allows the definition of input and output data types. |
| 252 | // These types can be objects, but also primitives and arrays. |
| 253 | // This object is based on the [JSON Schema Specification Draft 4](http://json-schema.org/) |
| 254 | // and uses a predefined subset of it. |
| 255 | // On top of this subset, there are extensions provided by this specification to allow for more complete documentation. |
| 256 | // |
| 257 | // For more information: http://goo.gl/8us55a#schemaObject |
| 258 | type Schema struct { |
| 259 | VendorExtensible |
| 260 | SchemaProps |
| 261 | SwaggerSchemaProps |
| 262 | ExtraProps map[string]interface{} `json:"-"` |
| 263 | } |
| 264 | |
| 265 | // JSONLookup implements an interface to customize json pointer lookup |
| 266 | func (s Schema) JSONLookup(token string) (interface{}, error) { |
| 267 | if ex, ok := s.Extensions[token]; ok { |
| 268 | return &ex, nil |
| 269 | } |
| 270 | |
| 271 | if ex, ok := s.ExtraProps[token]; ok { |
| 272 | return &ex, nil |
| 273 | } |
| 274 | |
| 275 | r, _, err := jsonpointer.GetForToken(s.SchemaProps, token) |
| 276 | if r != nil || (err != nil && !strings.HasPrefix(err.Error(), "object has no field")) { |
| 277 | return r, err |
| 278 | } |
| 279 | r, _, err = jsonpointer.GetForToken(s.SwaggerSchemaProps, token) |
| 280 | return r, err |
| 281 | } |
| 282 | |
| 283 | // WithID sets the id for this schema, allows for chaining |
| 284 | func (s *Schema) WithID(id string) *Schema { |
| 285 | s.ID = id |
| 286 | return s |
| 287 | } |
| 288 | |
| 289 | // WithTitle sets the title for this schema, allows for chaining |
| 290 | func (s *Schema) WithTitle(title string) *Schema { |
| 291 | s.Title = title |
| 292 | return s |
| 293 | } |
| 294 | |
| 295 | // WithDescription sets the description for this schema, allows for chaining |
| 296 | func (s *Schema) WithDescription(description string) *Schema { |
| 297 | s.Description = description |
| 298 | return s |
| 299 | } |
| 300 | |
| 301 | // WithProperties sets the properties for this schema |
| 302 | func (s *Schema) WithProperties(schemas map[string]Schema) *Schema { |
| 303 | s.Properties = schemas |
| 304 | return s |
| 305 | } |
| 306 | |
| 307 | // SetProperty sets a property on this schema |
| 308 | func (s *Schema) SetProperty(name string, schema Schema) *Schema { |
| 309 | if s.Properties == nil { |
| 310 | s.Properties = make(map[string]Schema) |
| 311 | } |
| 312 | s.Properties[name] = schema |
| 313 | return s |
| 314 | } |
| 315 | |
| 316 | // WithAllOf sets the all of property |
| 317 | func (s *Schema) WithAllOf(schemas ...Schema) *Schema { |
| 318 | s.AllOf = schemas |
| 319 | return s |
| 320 | } |
| 321 | |
| 322 | // WithMaxProperties sets the max number of properties an object can have |
| 323 | func (s *Schema) WithMaxProperties(max int64) *Schema { |
| 324 | s.MaxProperties = &max |
| 325 | return s |
| 326 | } |
| 327 | |
| 328 | // WithMinProperties sets the min number of properties an object must have |
| 329 | func (s *Schema) WithMinProperties(min int64) *Schema { |
| 330 | s.MinProperties = &min |
| 331 | return s |
| 332 | } |
| 333 | |
| 334 | // Typed sets the type of this schema for a single value item |
| 335 | func (s *Schema) Typed(tpe, format string) *Schema { |
| 336 | s.Type = []string{tpe} |
| 337 | s.Format = format |
| 338 | return s |
| 339 | } |
| 340 | |
| 341 | // AddType adds a type with potential format to the types for this schema |
| 342 | func (s *Schema) AddType(tpe, format string) *Schema { |
| 343 | s.Type = append(s.Type, tpe) |
| 344 | if format != "" { |
| 345 | s.Format = format |
| 346 | } |
| 347 | return s |
| 348 | } |
| 349 | |
| 350 | // CollectionOf a fluent builder method for an array parameter |
| 351 | func (s *Schema) CollectionOf(items Schema) *Schema { |
| 352 | s.Type = []string{"array"} |
| 353 | s.Items = &SchemaOrArray{Schema: &items} |
| 354 | return s |
| 355 | } |
| 356 | |
| 357 | // WithDefault sets the default value on this parameter |
| 358 | func (s *Schema) WithDefault(defaultValue interface{}) *Schema { |
| 359 | s.Default = defaultValue |
| 360 | return s |
| 361 | } |
| 362 | |
| 363 | // WithRequired flags this parameter as required |
| 364 | func (s *Schema) WithRequired(items ...string) *Schema { |
| 365 | s.Required = items |
| 366 | return s |
| 367 | } |
| 368 | |
| 369 | // AddRequired adds field names to the required properties array |
| 370 | func (s *Schema) AddRequired(items ...string) *Schema { |
| 371 | s.Required = append(s.Required, items...) |
| 372 | return s |
| 373 | } |
| 374 | |
| 375 | // WithMaxLength sets a max length value |
| 376 | func (s *Schema) WithMaxLength(max int64) *Schema { |
| 377 | s.MaxLength = &max |
| 378 | return s |
| 379 | } |
| 380 | |
| 381 | // WithMinLength sets a min length value |
| 382 | func (s *Schema) WithMinLength(min int64) *Schema { |
| 383 | s.MinLength = &min |
| 384 | return s |
| 385 | } |
| 386 | |
| 387 | // WithPattern sets a pattern value |
| 388 | func (s *Schema) WithPattern(pattern string) *Schema { |
| 389 | s.Pattern = pattern |
| 390 | return s |
| 391 | } |
| 392 | |
| 393 | // WithMultipleOf sets a multiple of value |
| 394 | func (s *Schema) WithMultipleOf(number float64) *Schema { |
| 395 | s.MultipleOf = &number |
| 396 | return s |
| 397 | } |
| 398 | |
| 399 | // WithMaximum sets a maximum number value |
| 400 | func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema { |
| 401 | s.Maximum = &max |
| 402 | s.ExclusiveMaximum = exclusive |
| 403 | return s |
| 404 | } |
| 405 | |
| 406 | // WithMinimum sets a minimum number value |
| 407 | func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema { |
| 408 | s.Minimum = &min |
| 409 | s.ExclusiveMinimum = exclusive |
| 410 | return s |
| 411 | } |
| 412 | |
| 413 | // WithEnum sets a the enum values (replace) |
| 414 | func (s *Schema) WithEnum(values ...interface{}) *Schema { |
| 415 | s.Enum = append([]interface{}{}, values...) |
| 416 | return s |
| 417 | } |
| 418 | |
| 419 | // WithMaxItems sets the max items |
| 420 | func (s *Schema) WithMaxItems(size int64) *Schema { |
| 421 | s.MaxItems = &size |
| 422 | return s |
| 423 | } |
| 424 | |
| 425 | // WithMinItems sets the min items |
| 426 | func (s *Schema) WithMinItems(size int64) *Schema { |
| 427 | s.MinItems = &size |
| 428 | return s |
| 429 | } |
| 430 | |
| 431 | // UniqueValues dictates that this array can only have unique items |
| 432 | func (s *Schema) UniqueValues() *Schema { |
| 433 | s.UniqueItems = true |
| 434 | return s |
| 435 | } |
| 436 | |
| 437 | // AllowDuplicates this array can have duplicates |
| 438 | func (s *Schema) AllowDuplicates() *Schema { |
| 439 | s.UniqueItems = false |
| 440 | return s |
| 441 | } |
| 442 | |
| 443 | // AddToAllOf adds a schema to the allOf property |
| 444 | func (s *Schema) AddToAllOf(schemas ...Schema) *Schema { |
| 445 | s.AllOf = append(s.AllOf, schemas...) |
| 446 | return s |
| 447 | } |
| 448 | |
| 449 | // WithDiscriminator sets the name of the discriminator field |
| 450 | func (s *Schema) WithDiscriminator(discriminator string) *Schema { |
| 451 | s.Discriminator = discriminator |
| 452 | return s |
| 453 | } |
| 454 | |
| 455 | // AsReadOnly flags this schema as readonly |
| 456 | func (s *Schema) AsReadOnly() *Schema { |
| 457 | s.ReadOnly = true |
| 458 | return s |
| 459 | } |
| 460 | |
| 461 | // AsWritable flags this schema as writeable (not read-only) |
| 462 | func (s *Schema) AsWritable() *Schema { |
| 463 | s.ReadOnly = false |
| 464 | return s |
| 465 | } |
| 466 | |
| 467 | // WithExample sets the example for this schema |
| 468 | func (s *Schema) WithExample(example interface{}) *Schema { |
| 469 | s.Example = example |
| 470 | return s |
| 471 | } |
| 472 | |
| 473 | // WithExternalDocs sets/removes the external docs for/from this schema. |
| 474 | // When you pass empty strings as params the external documents will be removed. |
| 475 | // When you pass non-empty string as one value then those values will be used on the external docs object. |
| 476 | // So when you pass a non-empty description, you should also pass the url and vice versa. |
| 477 | func (s *Schema) WithExternalDocs(description, url string) *Schema { |
| 478 | if description == "" && url == "" { |
| 479 | s.ExternalDocs = nil |
| 480 | return s |
| 481 | } |
| 482 | |
| 483 | if s.ExternalDocs == nil { |
| 484 | s.ExternalDocs = &ExternalDocumentation{} |
| 485 | } |
| 486 | s.ExternalDocs.Description = description |
| 487 | s.ExternalDocs.URL = url |
| 488 | return s |
| 489 | } |
| 490 | |
| 491 | // WithXMLName sets the xml name for the object |
| 492 | func (s *Schema) WithXMLName(name string) *Schema { |
| 493 | if s.XML == nil { |
| 494 | s.XML = new(XMLObject) |
| 495 | } |
| 496 | s.XML.Name = name |
| 497 | return s |
| 498 | } |
| 499 | |
| 500 | // WithXMLNamespace sets the xml namespace for the object |
| 501 | func (s *Schema) WithXMLNamespace(namespace string) *Schema { |
| 502 | if s.XML == nil { |
| 503 | s.XML = new(XMLObject) |
| 504 | } |
| 505 | s.XML.Namespace = namespace |
| 506 | return s |
| 507 | } |
| 508 | |
| 509 | // WithXMLPrefix sets the xml prefix for the object |
| 510 | func (s *Schema) WithXMLPrefix(prefix string) *Schema { |
| 511 | if s.XML == nil { |
| 512 | s.XML = new(XMLObject) |
| 513 | } |
| 514 | s.XML.Prefix = prefix |
| 515 | return s |
| 516 | } |
| 517 | |
| 518 | // AsXMLAttribute flags this object as xml attribute |
| 519 | func (s *Schema) AsXMLAttribute() *Schema { |
| 520 | if s.XML == nil { |
| 521 | s.XML = new(XMLObject) |
| 522 | } |
| 523 | s.XML.Attribute = true |
| 524 | return s |
| 525 | } |
| 526 | |
| 527 | // AsXMLElement flags this object as an xml node |
| 528 | func (s *Schema) AsXMLElement() *Schema { |
| 529 | if s.XML == nil { |
| 530 | s.XML = new(XMLObject) |
| 531 | } |
| 532 | s.XML.Attribute = false |
| 533 | return s |
| 534 | } |
| 535 | |
| 536 | // AsWrappedXML flags this object as wrapped, this is mostly useful for array types |
| 537 | func (s *Schema) AsWrappedXML() *Schema { |
| 538 | if s.XML == nil { |
| 539 | s.XML = new(XMLObject) |
| 540 | } |
| 541 | s.XML.Wrapped = true |
| 542 | return s |
| 543 | } |
| 544 | |
| 545 | // AsUnwrappedXML flags this object as an xml node |
| 546 | func (s *Schema) AsUnwrappedXML() *Schema { |
| 547 | if s.XML == nil { |
| 548 | s.XML = new(XMLObject) |
| 549 | } |
| 550 | s.XML.Wrapped = false |
| 551 | return s |
| 552 | } |
| 553 | |
| 554 | // MarshalJSON marshal this to JSON |
| 555 | func (s Schema) MarshalJSON() ([]byte, error) { |
| 556 | b1, err := json.Marshal(s.SchemaProps) |
| 557 | if err != nil { |
| 558 | return nil, fmt.Errorf("schema props %v", err) |
| 559 | } |
| 560 | b2, err := json.Marshal(s.VendorExtensible) |
| 561 | if err != nil { |
| 562 | return nil, fmt.Errorf("vendor props %v", err) |
| 563 | } |
| 564 | b3, err := s.Ref.MarshalJSON() |
| 565 | if err != nil { |
| 566 | return nil, fmt.Errorf("ref prop %v", err) |
| 567 | } |
| 568 | b4, err := s.Schema.MarshalJSON() |
| 569 | if err != nil { |
| 570 | return nil, fmt.Errorf("schema prop %v", err) |
| 571 | } |
| 572 | b5, err := json.Marshal(s.SwaggerSchemaProps) |
| 573 | if err != nil { |
| 574 | return nil, fmt.Errorf("common validations %v", err) |
| 575 | } |
| 576 | var b6 []byte |
| 577 | if s.ExtraProps != nil { |
| 578 | jj, err := json.Marshal(s.ExtraProps) |
| 579 | if err != nil { |
| 580 | return nil, fmt.Errorf("extra props %v", err) |
| 581 | } |
| 582 | b6 = jj |
| 583 | } |
| 584 | return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil |
| 585 | } |
| 586 | |
| 587 | // UnmarshalJSON marshal this from JSON |
| 588 | func (s *Schema) UnmarshalJSON(data []byte) error { |
| 589 | props := struct { |
| 590 | SchemaProps |
| 591 | SwaggerSchemaProps |
| 592 | }{} |
| 593 | if err := json.Unmarshal(data, &props); err != nil { |
| 594 | return err |
| 595 | } |
| 596 | |
| 597 | sch := Schema{ |
| 598 | SchemaProps: props.SchemaProps, |
| 599 | SwaggerSchemaProps: props.SwaggerSchemaProps, |
| 600 | } |
| 601 | |
| 602 | var d map[string]interface{} |
| 603 | if err := json.Unmarshal(data, &d); err != nil { |
| 604 | return err |
| 605 | } |
| 606 | |
| 607 | sch.Ref.fromMap(d) |
| 608 | sch.Schema.fromMap(d) |
| 609 | |
| 610 | delete(d, "$ref") |
| 611 | delete(d, "$schema") |
| 612 | for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) { |
| 613 | delete(d, pn) |
| 614 | } |
| 615 | |
| 616 | for k, vv := range d { |
| 617 | lk := strings.ToLower(k) |
| 618 | if strings.HasPrefix(lk, "x-") { |
| 619 | if sch.Extensions == nil { |
| 620 | sch.Extensions = map[string]interface{}{} |
| 621 | } |
| 622 | sch.Extensions[k] = vv |
| 623 | continue |
| 624 | } |
| 625 | if sch.ExtraProps == nil { |
| 626 | sch.ExtraProps = map[string]interface{}{} |
| 627 | } |
| 628 | sch.ExtraProps[k] = vv |
| 629 | } |
| 630 | |
| 631 | *s = sch |
| 632 | |
| 633 | return nil |
| 634 | } |