github.com/AngusLu/go-swagger@v0.28.0/docs/use/models/schemas.md (about) 1 # Schema generation rules 2 3 Lots of the work carried out by go-swagger is to generate models, which can have all kinds of rules like polymorphism and 4 validations. Go-swagger models are the go data structures used for serialization and validation. 5 6 Of course none of this is possible without a set of rules and trade-offs. 7 8 ### About schemas 9 10 A schema is a data structure specified in a Swagger document. Loosely speaking, a swagger schema corresponds to 11 a JSONSchema-draft4 schema (see [differences](#swagger-vs-jsonschema) below). 12 For each schema, `go-swagger` will generate one or more model types in go. 13 14 > **NOTE**: Swagger makes a distinction between schemas and "simple schemas". 15 > We use simple schemas to describe parameters and headers for operations. 16 > Simple schemas are supported by `go-swagger` (including validation), but are not rendered as standalone models. 17 > Rather, simple schema structures and validation methods are generated with the operation they are attached to. 18 > 19 > Models are dedicated to the description of Swagger schemas, which are described as a parameter body, a response or a 20 > spec definition. 21 22 #### Interfaces 23 24 The generated models implements: 25 26 - a serialization interface 27 - `MarshalJSON()`, `UnmarshalJSON()`: 28 - standard structures use JSON decoder tags (serialization tags are customizable) 29 - composed and extensible structures use custom marshalers (`allOf`, `additionalProperties`, tuples and polymorphic types) 30 - `MarshalBinary()`, `UnmarshalBinary()` interfaces (`encoding/BinaryMarshaler`, `encoding/BinaryUnmarshaler`), 31 which may use the fast [`mailru/easyjson`][easy-json] package 32 - a validation interface ([`go-openapi/runtime/Validatable`][Validatable]), with a `Validate(strfmt.Registry) error` method 33 34 Validation methods are wired at generation time, and rely mostly on native types: this makes validation faster than a 35 dynamic general purpose JSON schema validator. 36 37 Example of a generated structure: 38 ```golang 39 // Principal principal 40 // swagger:model principal 41 type Principal struct { 42 43 // name 44 Name string `json:"name,omitempty"` 45 46 // roles 47 Roles []string `json:"roles"` 48 } 49 ``` 50 51 > **NOTE**: if you are looking for a **dynamic**, fully JSONSchema compliant, general purpose validator, 52 > the [`go-openapi/validate`][validate] package 53 > is what you want. It is fully tested against the JSONSchema-Test-Suite (supports JSON-schema-draft4). 54 > See a working example [here][validate-json]. 55 56 #### Mapping patterns 57 58 The general idea is that you should rarely see `interface{}` in the generated code: 59 you get a complete representation of a swagger document in somewhat idiomatic go. 60 61 There is set of mapping patterns that are applied to transform a spec into go types: 62 63 * definition of primitive => type alias/name 64 * definition of array => type alias/name 65 * definition of map => type alias/name 66 * definition of object with properties => struct 67 * definition of $ref => type alias/name 68 * object with only additional properties => map[string]T 69 * object with additional properties and properties => custom serializer 70 * schema with schema array in items => tuple (struct with properties, custom serializer) 71 * schema with all of => struct 72 * all of schema with ref => embedded value 73 * all of schema with properties => properties are included in struct 74 * adding an all of schema with just `x-isnullable`: true or `x-nullable`: true turns 75 the schema into a pointer when there are only other extension properties provided 76 * additional items in tuples => 77 JSONSchema and by extension swagger allow for items that have a fixed size array 78 with schema's describing the items at each index. This can be combined with additional items 79 to form some kind of tuple with varargs. 80 To map this to go it creates a struct that has fixed names and a custom json serializer. 81 82 #### Minimal use of go's reflection 83 84 Generated models uses _no reflection_ except for `enum` and `required` validations. This makes validation faster. 85 86 #### Doc strings 87 88 All documentation items provided by the spec are integrated as godoc-friendly comments in the 89 generated source. You may look at how a trivial example is rendered [here][go-doc-model]. 90 91 The code that is generated also gets the same doc comments that are used by the scanner 92 to generate a spec from go code (e.g. comments like `// swagger:xxx`). 93 So that after generation you should be able to reverse-generate a spec from the code that was generated by your spec. 94 It should be equivalent to the original spec but might miss some default values and examples. 95 96 #### Types reusability 97 98 Models can be generated independently from other components of your API. 99 Internal model structures may thus be safely regenerated if the contract at your endpoints does not change. 100 101 ##### Reusing previous generations 102 103 Previously generated models can be reused when constructing a new API server or client (e.g. using `swagger generate server --model=[my existing package]`). 104 105 The generator makes every effort to keep the go code readable, idiomatic and commented: models may thus be manually customized or extended. 106 Such customized types may be later on reused in other specs, using the `x-go-type` extension. 107 108 109 ### Swagger vs JSONSchema 110 111 A Swagger 2.0 schema corresponds by and large to a JSON-schema-draft4. However, there are some substantial differences (see [swagger]): 112 113 In JSONSchema, but _not_ in Swagger 2.0: 114 115 - `anyOf`, `oneOf` and `not` constructs are not supported (this is for OpenAPI 3) 116 - the `null` type is not supported (the `nullable` keyword is defined in OpenAPI 3) 117 - `additionalItems` are not supported (go-swagger does support it) 118 - `patternProperties` are not supported 119 - `dependencies` are not supported 120 - multiple types, defined as `type: [ ... ]` are not supported 121 122 Conversely, what we have in Swagger 2.0, but _not_ in JSON-schema: 123 124 - the `discriminator` attribute controls polymorphism ([see below](#polymorphic-types)) 125 - properties may be given a [`readOnly` attribute][read-only] (same as in JSONSchema-draft7) 126 - `array` types **must** have an `items` restriction 127 - `format` supports more values for strings and numbers 128 129 Other minor differences: 130 131 - `default` values **must** validate their schema 132 - types `array` **must** have an `items` specification 133 - extensions may be specified as special `x-...` annotations. Go-swagger defines [some custom tags](#custom-extensions) to customize generated code. 134 - other available attributes: `example`, `xml` and `externalDocs` 135 136 > **NOTE**: `example` and `externalDocs` do not currently influence models generation. 137 138 ### Go-swagger vs Swagger 139 140 go-swagger models implements _almost_ all Swagger 2.0 schema features. 141 142 We also wanted to support as much JSONSchema features as possible: the model generator may be used independently 143 to generate data structures using the Swagger specification as a serialization description language. 144 145 There are some small differences or implementation details to be aware of. 146 147 | Feature | JSON-schema-draft4 | Swagger 2.0 | go-swagger | Comment | 148 |--- |--- |--- |--- |--- | 149 | `"format"` | Y| Y | Y | Formats are provided by the extensible [`go-openapi/strfmt` package][strfmt]. See also [here](#formatted-types)| 150 | `"additionalProperties": {schema}` | Y| Y | Y | Rendered as `map[string]T` | 151 | `"additionalProperties": boolean` | Y| Y | partial| Rendered as `map[string]interface{}` | 152 | `"additionalItems": {schema}` | Y| **N**| Y | Rendered with [tuple models](#tuples-and-additional-items)| 153 | `"additionalItems": boolean` | Y| **N**| partial| See [extensible types](#extensible-types) | 154 | empty object: `{ "type": "object"}` | Y| Y | Y | Rendered as `interface{}` (anything) rather than `map[string]inferface{}` (any JSON object, e.g. not arrays)| 155 | `"pattern"` | Y| Y | partial| Speed for strictness trade-off: support go regexp, which slighty differ from JSONSchema ECMA regexp (e.g does not support backtracking)| 156 | large number, arbitrary precision | Y| **N**| N | | 157 | `"readOnly"` | N| Y | Y | | 158 | `"type": [ "object", ... ]` | Y| N | N | JSONSchema multiple types are not supported: use Swagger polymorphism instead| 159 | implicit type from values in `enum` | Y| ? | N | As of v0.15, when the type is empty, the object is rendered as `interface{}` and the `enum` constraint is ignored| 160 | tuple `type: "array" items:[...] | Y| Y | partial| As of v0.15, incomplete tuples and tuples with array validation are not properly validated| 161 162 163 JSONSchema defaults to `"additionalProperties": true`, `go-swagger` defaults to ignoring extra properties. Same for `additionalItems`. 164 165 When`"additionalProperties": false` (resp. `"additionalItems": false`), uwanted properties (resp. items) do not invalidate data 166 but they are not kept in the model. 167 168 This is the default if `additionalProperties` (resp. `additionalItems`) is not provided. 169 It is an optimization as it makes the code simpler (and faster) for most use cases. 170 Explicitly specifying `true` will produce models that retain those additional properties (resp. items). 171 172 ### Known limitations with go-swagger models 173 174 Recap as of release `>0.26`: 175 176 - re [JSON-schema-draft4][json-schema] 177 178 - `"additionalProperties": false`, `"additionalItems": false` do not invalidate data with extra properties. We trade strictness for speed and 179 truncate unwanted properties or items without further validation. 180 - the generation flag `--strict-additional-properties` invalidates data with extra properties when `"additionalProperties": false` 181 - when `enum` values cannot be marshalled into their schema, a runtime panic occurs - the `go-openapi/validate` package does not yet detect this situation 182 - `patternProperties` and `dependencies`are not supported 183 - use of `additionalItems` requires the `--skip-validation` flag (`go-openapi/validate` is strict regarding Swagger specification) 184 - JSONSchema defaults to the `"additionalProperties": true`, `go-swagger` defaults to ignoring extra properties. Same for `additionalItems`. 185 - array validations (`minItems`, etc.) are not yet supported for tuples, as of v0.15 186 - objects with no properties and no additional properties schema have no validation at all (e.g. passing an array is not invalid) (rendered as `interface{}`) 187 - `null` JSON type: the `null` type is not supported by Swagger - use of the `x-nullable` extension makes `null` values valid 188 (notice that combining the use of `required` and `x-nullable` is not fully JSONSchema compliant - see [below](#nullability)) 189 190 ### Custom extensions 191 192 Model generation may be altered with the following extensions: 193 194 - `x-go-name: "string"`: give explicit type name to the generated model 195 - `x-go-custom-tag: "string"`: add serialization tags to an object property (see [Customizing struct tags](#customizing-struct-tags)) 196 - `x-nullable: true|false` (or equivalently `x-is-nullable:true|false`): accepts null values (i.e. rendered as a pointer) 197 - `x-go-type: "string"`: explicitly reuse an already available go type 198 - `x-class: "string"`: give explicit polymorphic class name in discriminator 199 - `x-order: number`: indicates explicit generation ordering for schemas (e.g. models, properties, allOf, ...) 200 - `x-omitempty: true|false`: force the omitempty modifier in struct json and xml tags 201 - `x-go-json-string: true:false`: force the string modifier in struct json tags 202 203 ### Primitive types 204 205 Swagger types are rendered as follows by `go-swagger`: 206 207 | Swagger type | go type | 208 |-----------------------------|----------| 209 | `string` (no format) | `string` | 210 | `boolean` | `bool` | 211 | `number` | `float64`| 212 | `number format double` | `float64`| 213 | `number format float` | `float32`| 214 | `integer` | `int64` | 215 | `integer format int64` | `int64` | 216 | `integer format int32` | `int32` | 217 | `integer format uint64` | `uint64` | 218 | `integer format uint32` | `uint32` | 219 | `file` | `io.ReadCloser`(server) or `io.Writer` (client)| 220 | `string format binary` | `io.ReadCloser`or `io.Writer`| 221 | `string` with other formats | corresponding type exported by `go-openapi/strfmt` | 222 223 The `file` type is exposed as a `io.ReadCloser` (or `io.Writer`) interface. The actual implementation in a 224 runtime server or client is provided by the [`go-openapi/runtime/File` type][File]. 225 226 ### Formatted types 227 228 The `go-openapi/strfmt` packages provides a number of predefined "formats" for JSON string types. 229 The full list of formats supported by this package is [here][all-formats] 230 231 ### Nullability 232 233 Here are the rules that turn something into a pointer. 234 * structs 235 * `x-nullable`, `x-isnullable`: explicit override to accept null values (otherwise not accepted by Swagger) 236 * required property 237 * extending with `allOf` a schema with another schema with just `x-nullable` (or other extensions, 238 but no new properties) turns the schema into a pointer 239 240 Primitive types (number, bool and string) are turned into pointers whenever: 241 * we need to validate valid zero values vs unset (i.e. the zero value is explicitly checked against validation) 242 243 Examples: 244 ```yaml 245 definitions: 246 myInteger: 247 type: integer 248 minimum: 0 249 myString: 250 type: string 251 minLength: 0 252 ``` 253 254 Yields: 255 ```go 256 type MyInteger *int64 257 ... 258 type MyString *string 259 ``` 260 261 Notice that the following equivalent does not produce a pointer: 262 ```yaml 263 definitions: 264 myInteger: 265 type: integer 266 format: uint64 267 ``` 268 269 > NOTE: read-only properties are not rendered as pointers. 270 271 API developers may use the conversion utilities provided by the `go-openapi/swag` and `go-openapi/strfmt/conv` packages 272 to manipulate pointers more easily. 273 274 > **Known limitations**: 275 > pointers are used to distinguish in golang a zero value from no value set. 276 > 277 > This design comes with some shortcomings: 278 > 279 > - it is built around the validation use case. 280 > In the general case it is not possible to know if a value has been set 281 > to a zero value when the type is not a pointer. In cases where this is 282 > important, use the `x-nullable` extension 283 > - using `null` as a proxy for unset, makes uneasy the explicit use of the JSON `null` type 284 > Swagger APIs are not supposed to carry `null` values. 285 > `go-swagger` generated APIs can, using the `x-nullable` extension, and it is then not possible 286 > to distinguish a field explicitly set to `null` from an unset field 287 > 288 > An alternate design has been experimented but not released. For those interested in pushing forward this project again, 289 > see [this pull request][lifting-pointers] 290 291 #### Common use cases 292 293 You don't always have to resort to pointers to figure out whether a value is empty. 294 295 * The idiomatic way to check for a null/empty string is: `minLength: 1` 296 297 ### Validation 298 299 All produced models implement the [Validatable] interface. 300 301 Exceptions: 302 - `file` types do not support validation (however generated operations may check the `maxLength` of a file) 303 - empty schemas (`any` type, rendered as `interface{}`) do not support validation 304 305 Therefore, type aliases constructed on either a swagger `file` or an empty schema does not implement this interface. 306 307 Validation errors: 308 - Returned errors are supported by the `go-openapi/errors/Error` type, which supports errors codes and composite errors. 309 310 Validation stops assessing errors down to the property level and does not continue digging all nested strutures as soon 311 as an error is found. 312 313 ### Type aliasing 314 315 A definition may create an _aliased_ type like this: 316 317 ```yaml 318 definitions: 319 myDate: 320 type: string 321 format: date 322 ``` 323 324 Rendered as: 325 ```go 326 type MyDate strfmt.Date 327 ``` 328 329 Notice that setting `x-nullable: true` in such an alias will not render the type itself into a pointer, but rather, 330 all containers of his type will use it as a pointer. 331 332 Example: 333 ```yaml 334 definitions: 335 myDate: 336 type: string 337 format: date 338 x-nullable: true 339 anArrayOfDates: 340 type: array 341 items: 342 $ref: '#/definitions/myDate' 343 ``` 344 345 Yields: 346 ```go 347 type MyDate strfmt.Date 348 ... 349 type AnArrayOfDates []*MyDate 350 ``` 351 352 Realiasing 353 354 Given the above definitions, we add: 355 356 ```yaml 357 ... 358 herDate: 359 $ref: #/definitions/myDate 360 hisDate: 361 $ref: #/definitions/herDate 362 ``` 363 364 Rendered as (requires go1.9+): 365 ```go 366 type HerDate = MyDate 367 ``` 368 369 ```go 370 type HisDate = HerDate 371 ``` 372 373 ### Extensible types 374 375 ##### Objects and additional properties 376 377 Additional properties in a JSON object are represented in a go struct by `map[string]T`. 378 379 Examples: 380 381 ```yaml 382 definitions: 383 extensibleObject: 384 properties: 385 prop1: 386 type: integer 387 additionalProperties: 388 type: string 389 format: date 390 ``` 391 392 Is rendered as: 393 ```golang 394 type ExtensibleObject struct { 395 Prop1 int64 396 ExtensibleObjectProperties map[string]strfmt.Date 397 } 398 ``` 399 400 If there is no restriction on the additional properties: 401 402 ```yaml 403 definitions: 404 extensibleObject: 405 type: object 406 properties: 407 prop1: 408 type: integer 409 additionalProperties: true 410 ``` 411 412 We get: 413 ```golang 414 type ExtensibleObject struct { 415 Prop1 int64 416 ExtensibleObjectProperties map[string]interface{} 417 } 418 ``` 419 420 ##### Tuples and additional items 421 422 A tuple is rendered as a structure with a property for each element of the tuple. 423 424 Example: 425 ```yaml 426 definitions: 427 tuple: 428 type: array 429 items: 430 - type: integer 431 - type: string 432 - type: string 433 format: uuid 434 ``` 435 436 Gives: 437 ```golang 438 type Tuple struct { 439 P0 *int64 440 P1 *string 441 P2 *strfmt.UUID 442 } 443 ``` 444 445 If we specify additional items as in: 446 ```yaml 447 definitions: 448 extensibleTuple: 449 type: array 450 items: 451 - type: integer 452 - type: string 453 - type: string 454 format: uuid 455 additionalItems: 456 - type: number 457 ``` 458 Gives: 459 ```golang 460 type ExtensibleTuple struct { 461 P0 *int64 462 P1 *string 463 P2 *strfmt.UUID 464 ExtensibleTupleItems []float64 465 } 466 ``` 467 468 > **NOTE**: currently the P0, P1, ... names are not customizable. 469 470 ### Polymorphic types 471 472 Polymorphic types are swagger's flavor for inheritance (aka _hierarchized composition_...). 473 The use of the `discriminator` keyword gives a special meaning to `allOf` compositions. 474 475 #### Base types 476 Whenever the special attribute `discriminator` is used, this means this object definition is 477 a base type, to be used to extend other types, or subtypes. 478 479 The discriminator property indicates which subtype is used whenever an instance of the base type is found. 480 The discriminator's possible values are the names of the subtypes (no aliasing is supported in Swagger 2.0). 481 482 > **NOTE**: the discriminator is a `required` property with `"type": "string"`. 483 > No validation attached to this property, save `required`, will be honored, as 484 > a discriminator property is implicitly an `enum` with all the subtype names found in the spec. 485 486 The base type must be a JSON-schema object (it has at least one property, the discriminator). 487 It may define other properties than the discriminator. Like `name` in this example. 488 489 Example: 490 ```yaml 491 Pet: 492 type: object 493 discriminator: petType 494 properties: 495 name: 496 type: string 497 petType: 498 type: string 499 required: 500 - name 501 - petType 502 ``` 503 504 A base type is rendered as an interface, with getter/setter funcs on all attributes. 505 506 ```go 507 // Pet pet 508 // swagger:discriminator Pet petType 509 type Pet interface { 510 runtime.Validatable 511 512 // name 513 // Required: true 514 Name() *string 515 SetName(*string) 516 517 // pet type 518 // Required: true 519 PetType() string 520 SetPetType(string) 521 } 522 ``` 523 524 > **NOTE**: an unexported reference concrete type is also generated, but not currently used by models. 525 526 #### Subtypes 527 528 A subtype _extends_ a base type. It is defined by composing the base type with an `allOf` construct. 529 All subtypes implement the interface of their base type. So in this examples, all instances of `Dog` may pretend 530 to be a `Pet`. 531 532 Example: 533 ```yaml 534 Dog: 535 type: object 536 description: A representation of a dog 537 allOf: 538 - $ref: '#/definitions/Pet' 539 - properties: 540 packSize: 541 type: integer 542 format: int32 543 description: the size of the pack the dog is from 544 default: 0 545 minimum: 0 546 required: 547 - packSize 548 ``` 549 550 Yields: 551 ```go 552 // Dog A representation of a dog 553 // swagger:model Dog 554 type Dog struct { 555 nameField *string 556 557 // the size of the pack the dog is from 558 // Required: true 559 // Minimum: 0 560 PackSize *int32 `json:"packSize"` 561 } 562 563 // Name gets the name of this subtype 564 func (m *Dog) Name() *string { 565 return m.nameField 566 } 567 568 // SetName sets the name of this subtype 569 func (m *Dog) SetName(val *string) { 570 m.nameField = val 571 } 572 573 // PetType gets the pet type of this subtype 574 func (m *Dog) PetType() string { 575 return "Dog" 576 } 577 578 // SetPetType sets the pet type of this subtype 579 func (m *Dog) SetPetType(val string) { 580 581 } 582 ``` 583 584 Notice the unexported fields which correspond to the description of the base type. 585 The properties of the base type are available with getter/setter functions. 586 587 > **NOTE**: if you expand your spec, the `allOf` semantics are lost. 588 > Do not expand specs with polymorphic types for code generation. 589 590 You may define several such derived types. 591 592 Example: 593 ```yaml 594 cat: 595 type: object 596 description: A representation of a cat 597 allOf: 598 - $ref: '#/definitions/Pet' 599 - properties: 600 huntingSkill: 601 type: string 602 description: The measured skill for hunting 603 default: lazy 604 enum: 605 - clueless 606 - lazy 607 - adventurous 608 - aggressive 609 required: 610 - huntingSkill 611 ``` 612 613 ```go 614 // Cat A representation of a cat 615 // swagger:model cat 616 type Cat struct { 617 nameField *string 618 619 // The measured skill for hunting 620 // Required: true 621 // Enum: [clueless lazy adventurous aggressive] 622 HuntingSkill *string `json:"huntingSkill"` 623 } 624 625 // Name gets the name of this subtype 626 func (m *Cat) Name() *string { 627 return m.nameField 628 } 629 630 // SetName sets the name of this subtype 631 func (m *Cat) SetName(val *string) { 632 m.nameField = val 633 } 634 635 // PetType gets the pet type of this subtype 636 func (m *Cat) PetType() string { 637 return "cat" 638 } 639 640 // SetPetType sets the pet type of this subtype 641 func (m *Cat) SetPetType(val string) { 642 643 } 644 ``` 645 646 Notice that the value of the discriminator field is case sensitive, e.g. `"Dog"` and `"cat"` above. 647 648 #### Type composition 649 650 Base types and subtypes may be used in other constructs. While subtypes are mostly handled like ordinary objects, 651 there are special provisions taken to generate new types composing base types. 652 653 Example: 654 ```yaml 655 Kennel: 656 type: object 657 required: 658 - pets 659 properties: 660 id: 661 type: integer 662 format: int64 663 pets: # <-- this may contain Cats and Dogs 664 type: array 665 items: 666 $ref: "#/definitions/Pet" 667 ``` 668 669 Yields: 670 ```go 671 // Kennel kennel 672 // swagger:model Kennel 673 type Kennel struct { 674 675 // id 676 ID int64 `json:"id,omitempty"` 677 678 petsField []Pet 679 } 680 681 // Pets gets the pets of this base type 682 func (m *Kennel) Pets() []Pet { 683 return m.petsField 684 } 685 686 // SetPets sets the pets of this base type 687 func (m *Kennel) SetPets(val []Pet) { 688 m.petsField = val 689 } 690 ``` 691 692 > **NOTE**: this representation with unexported fields for references to base types might be subject to change in 693 > the future, as it is not consistent in all cases. If you are intested to participate this design work, 694 > feel free to comment and express your views [here](https://github.com/go-swagger/go-swagger/issues/232). 695 696 #### Factories for base types 697 698 Subtypes and composed types have custom [un]marshallers. 699 700 Unmarshalling a base type is not carried through the standard MarshalJSON()/UnmarshalJSON() pair, but with 701 factories created for each base type. 702 703 Example: 704 ```go 705 // UnmarshalPet unmarshals polymorphic Pet 706 func UnmarshalPet(reader io.Reader, consumer runtime.Consumer) (Pet, error) 707 708 // UnmarshalPetSlice unmarshals polymorphic slices of Pet 709 func UnmarshalPetSlice(reader io.Reader, consumer runtime.Consumer) ([]Pet, error) 710 ``` 711 712 Note that the marshalling of a base type into JSON is processed naturally, so there is no need for a special function. 713 714 > **Known limitations**: 715 > As of v0.15, there are still some known limitations: 716 > 717 > - Unmarshalling maps of base types is not supported at the moment (e.g. `UnmarshalPetMap()` factory) 718 > - More complex constructs like `[][]Pet`, `[]map[string]Pet` are not supported yet 719 > - composing tuples containing base types is not supported yet 720 721 ### Serialization interfaces 722 723 <!-- 724 725 JSON 726 727 XML 728 --> 729 730 ##### Custom serializers 731 732 Tags are generally sufficient to provide proper JSON marshalling capabilities. 733 734 Models define some custom [un]marshallers in the following situations: 735 - tuples: array elements are dispatched in the tuple's struct 736 - additionalProperties: additional content is dispatched in the `map[string]...` 737 - subtypes of base types 738 - types composed of base types 739 - aliases on formatted types when the underlying type is not string (e.g. Date, Datetime) 740 741 <!-- 742 ##### [Un]MarshalBinary interfaces 743 744 TODO 745 --> 746 747 <!-- References --> 748 749 ##### External types 750 751 External types refer to custom type definitions, short-circuiting the use of generated models. 752 753 This is helpful for use-cases when custom marshaling or validation is needed. 754 755 Models may also be generated once, customized manually, then reused in spec as external types. 756 757 The extension annotation to declare an external type is `x-go-type`. 758 759 A complete example is provided [here](../../../examples/external-types/swagger-external.yaml) 760 to illustrate the different capabilities to inject custom types. 761 762 763 Examples: 764 765 External types are typically used in top-level model definitions, like so: 766 767 ```yaml 768 definitions: 769 myType: 770 type: object 771 x-go-type: 772 type: MyExternalType # <- abide by go conventions! The type must be exported 773 import: 774 package: github.com/example/models/custom # <- use fully qualified package names 775 ``` 776 777 Such definitions do not produce any generated model. 778 779 References in the generated code to this type will produce code like this: 780 781 ```go 782 custom.MyExternalType 783 ``` 784 785 If no package is provided, it defaults to the models package indicated for codegen: 786 ```yaml 787 definitions: 788 generatedType: 789 type: array 790 items: 791 $ref: '#/definitions/myType' 792 793 myType: 794 type: object 795 x-go-type: 796 type: MyExternalType 797 ``` 798 799 ```sh 800 swagger generate models --model-package custom --target ./codegen 801 802 ls ./codegen/custom # <- myType is NOT GENERATED 803 cat ./codegen/custom/generated_type.go 804 ``` 805 806 ```go 807 package custom 808 809 type GeneratedType []MyType 810 ``` 811 812 External types may also be injected at lower schema levels: 813 814 ```yaml 815 definitions: 816 MyType: 817 type: array 818 items: 819 type: string 820 x-go-type: 821 type: MyExternalString 822 import: 823 package: github.com/example/models/custom 824 ``` 825 or: 826 ```yaml 827 MyObject: 828 type: object 829 properties: 830 p1: 831 x-go-type: 832 type: RawMessage 833 import: 834 package: encoding/json 835 hints: 836 kind: interface 837 ``` 838 839 This also works for inlined types defined at the operation level: 840 841 ```yaml 842 parameters: 843 - in: body 844 name: corpus 845 schema: 846 type: object 847 x-go-type: 848 type: MyExternalStruct 849 import: 850 package: github.com/example/models/custom 851 ``` 852 853 > **NOTE**: when defining inline arrays or maps, you should know that the external type is 854 > not considered nullable by default. 855 > 856 > Therefore, unless you explicitly hint the generator to consider it nullable, you'll 857 > get constructs such as `[]external.MyType` or `map[string]external.MyType` instead of `[]*external.MyType` 858 > and `map[string]*external.MyType` respectively. You can use the `nullable` hint or the `x-nullable` extension 859 > to control this behavior. 860 861 ###### Known limitations 862 863 * External types only apply to schema objects. Simple swagger types 864 used in operations for query or path parameters or for response headers 865 cannot be externalized at this moment. 866 867 * Inlined external types cannot be declared inside polymorphic types (discriminated types). 868 869 * Inlined external types cannot be declared as embedded. Only top-level definitions are supported. 870 871 872 ###### External package aliasing 873 874 875 The following example replaces all references to `myModel` by `github.com/example/models/MyCustomModel`. 876 877 Example: 878 879 ```yaml 880 definitions: 881 myModel: 882 type: object 883 x-go-type: 884 type: MyCustomModel 885 import: 886 package: github.com/example/models 887 ``` 888 889 Note that the external model must implement the `github.com/go-openapi/runtime.Validatable` interface: it must know how to validate a schema. 890 No model is generated for this definition. 891 892 External packages may be imported with an alias, like so: 893 894 ```yaml 895 parameters: 896 in: body 897 schema: 898 type: object 899 x-go-type: 900 type: MyExternalStruct 901 import: 902 package: github.com/example/models/custom 903 alias: fred 904 ``` 905 906 Imports will look like so: 907 ```go 908 import ( 909 fred "github.com/example/models/custom" 910 ) 911 ... 912 ``` 913 914 Some deconfliction with other known import is applied automatically. Automatic deconfliction is not perfect, though. 915 916 For example: 917 ```yaml 918 MyObject: 919 type: object 920 properties: 921 p1: 922 x-go-type: 923 type: RawMessage 924 import: 925 package: encoding/json 926 hints: 927 kind: interface 928 ``` 929 930 ```go 931 import ( 932 jsonext "encoding/json" 933 ) 934 ``` 935 936 937 ###### Embedding external types 938 939 Sometimes, it is impractical to impose the constraint that the external type has a validation method. 940 You can then use the "embedded" option to create an embedded type based on the external model, and wraps the Validate 941 method. 942 943 Example: 944 ```yaml 945 definitions: 946 Time: 947 type: string 948 format: date-time # <- documentary only (external types takes over). This has no impact on generation. 949 x-go-type: 950 type: Time 951 import: 952 package: time 953 embedded: true 954 ``` 955 956 This example generates a wrapper type in the package model with a `Validate` method like this: 957 958 ```go 959 import ( 960 timeext "time" 961 962 "github.com/go-openapi/runtime" 963 "github.com/go-openapi/strfmt" 964 "github.com/go-openapi/swag" 965 ) 966 967 // Time time 968 // 969 // swagger:model Time 970 type Time struct { 971 timeext.Time 972 } 973 974 func (m Time) Validate(formats strfmt.Registry) error { 975 var f interface{} = m.Time 976 if v, ok := f.(runtime.Validatable); ok { 977 return v.Validate(formats) 978 } 979 return nil 980 } 981 ``` 982 983 The generated `Validate` method uses any existing `Validate` method or just returns `nil` (i.e. data is valid). 984 985 > **NOTE**: at the moment, we do not support the `format` specification over the embedded type. Format will be documentary only in that case. 986 987 Other examples: 988 ```yaml 989 Raw: 990 x-go-type: 991 type: RawMessage 992 import: 993 package: encoding/json 994 hints: 995 kind: primitive 996 embedded: true 997 ``` 998 ```go 999 import ( 1000 ... 1001 jsonext "encoding/json" 1002 ... 1003 ) 1004 1005 type Raw struct { 1006 jsonext.RawMessage 1007 } 1008 1009 func (m Raw) Validate(formats strfmt.Registry) error { 1010 var f interface{} = m.RawMessage 1011 if v, ok := f.(runtime.Validatable); ok { 1012 return v.Validate(formats) 1013 } 1014 return nil 1015 } 1016 ``` 1017 1018 You can embed types as pointers just the same. 1019 1020 Example: 1021 ```yaml 1022 definitions: 1023 Time: 1024 type: string 1025 x-go-type: 1026 type: Time 1027 import: 1028 package: time 1029 hints: 1030 nullable: true # <- nullable here refers to the nullability of the embedded external type 1031 embedded: true 1032 ``` 1033 1034 ```go 1035 type Time struct { 1036 *time.Time 1037 } 1038 ``` 1039 1040 1041 Using external types is powerful, but normally you still have to describe your type in the specification. That is expected, 1042 since this is how you document your API. 1043 1044 If you don't (that is the type referred to doesn't correspond to the type in the spec), then the generator may fail to produce correct code, 1045 because it simply has no way to infer what _kind_ of object is being referred to. 1046 1047 To solve this kind of problem, you may hint the generator to produce a correct usage of the external types, even though the specification 1048 doesn't reflect the correct nature of the object. 1049 1050 Example: 1051 ```yaml 1052 definitions: 1053 Error: 1054 type: object 1055 1056 Hotspot: 1057 x-go-type: 1058 type: Hotspot 1059 import: 1060 package: github.com/go-swagger/go-swagger/fixtures/enhancements/2224/external 1061 hints: 1062 kind: object 1063 x-nullable: true 1064 ``` 1065 In this example, the `Hotspot` schema is empty in the specification. The generator therefore can only guess that this is some `interface{}` type. 1066 Now thanks to the hint `kind: object`, we instruct the generator to expect an object so as to correctly reference this object. 1067 1068 1069 ###### Validation of external types 1070 1071 By default, the generator assumes that external types can be validated and will generate code that calls the "Validate" 1072 method of the type. 1073 1074 This can be disabled by providing an explicit hint: 1075 ```yaml 1076 MyObject: 1077 type: object 1078 properties: 1079 p1: 1080 x-go-type: 1081 type: RawMessage 1082 import: 1083 package: encoding/json 1084 hints: 1085 noValidation: true 1086 ``` 1087 1088 External types with an hint type "interface" or "stream" do not call validations. 1089 1090 Embedded types use type assertion to dynamically determine if the external type implements the `runtime.Validatable` interface. 1091 1092 1093 ###### External type hints 1094 1095 The generator does not attempt to introspect external types. They may even not exist at generation time. 1096 1097 Therefore, the generator has no idea of whether it is safe to generate pointers to the external type. 1098 1099 By default, external types are considered non nullable. This can be altered with the nullable hint or 1100 by hinting a type that is considered nullable (such as "object"). 1101 1102 Supported hints: 1103 ```yaml 1104 x-go-type: 1105 type: {external type name (exported symbol, without package qualifier)} 1106 import: 1107 package: {fully qualified package name - defaults to the target models defined by the --model-package flag} 1108 hints: 1109 kind: {map|object|array|interface|primitive|tuple|stream} 1110 noValidation: true|false # <- skips validation: defaults to true for embedded types, defaults to false for non-embedded, always false for kinds interface and stream 1111 nullable: true|false # <- default to true for kinds object,primitive and tuple 1112 embedded: true|false # <- defaults to false, generates a struct that wraps the external type 1113 ``` 1114 1115 ###### Caveats with imports 1116 1117 At this moment, external packages and aliases are deconflicted against other known imports and variables. 1118 1119 Example: 1120 ```yaml 1121 MyObject: 1122 type: object 1123 properties: 1124 p1: 1125 x-go-type: 1126 type: RawMessage 1127 import: 1128 package: encoding/json 1129 hints: 1130 kind: interface 1131 ``` 1132 1133 will generate an import deconflicted against the standard lib import: 1134 ```go 1135 import( 1136 ... 1137 jsonext "encoding/json" 1138 ... 1139 ) 1140 ``` 1141 1142 ###### External package aliasing 1143 1144 External packages may be imported with an alias, like so: 1145 1146 ```yaml 1147 parameters: 1148 in: body 1149 schema: 1150 type: object 1151 x-go-type: 1152 type: MyExternalStruct 1153 import: 1154 package: github.com/example/models/custom 1155 alias: fred 1156 ``` 1157 1158 Imports will look like so: 1159 ```go 1160 import ( 1161 fred "github.com/example/models/custom" 1162 ) 1163 ... 1164 ``` 1165 1166 Some deconfliction with other known imports is applied automatically. Automatic deconfliction is not perfect, though. 1167 1168 For example: 1169 ```yaml 1170 MyObject: 1171 type: object 1172 properties: 1173 p1: 1174 x-go-type: 1175 type: RawMessage 1176 import: 1177 package: encoding/json 1178 hints: 1179 kind: interface 1180 ``` 1181 1182 ```go 1183 import ( 1184 jsonext "encoding/json" 1185 ) 1186 ``` 1187 1188 Package aliases may still conflict with packages produces by operation tags or other external imports. 1189 1190 In such cases, modify the type alias under `x-go-type` to resolve the conflict manually. 1191 1192 ### Customizing struct tags 1193 1194 When a model struct is generated, tags for json are generated to keep the original name: 1195 1196 ```go 1197 type ObjectWithTag struct { 1198 StandardTag string `json:"standardTag,omitempty"` 1199 } 1200 ``` 1201 1202 #### Extra tags 1203 1204 Extra tags may be defined with the CLI generation option `--sruct-tags`. 1205 1206 Extra tags essentially repeat the name of the field can be added from the command line option. 1207 1208 > **NOTE**: at this moment, all tag modifiers (omitempty, string) are repeated like for the json tag. 1209 1210 ```bash 1211 swagger generate model ... --struct-tags yaml,db 1212 ``` 1213 1214 ```go 1215 type ObjectWithTag struct { 1216 StandardTag string `json:"standardTag,omitempty" yaml:"standardTag,omitempty" db:"standardTag,omitempty"` 1217 } 1218 ``` 1219 1220 #### Custom tags 1221 1222 A custom may be added to a field using the `x-go-custom-tag` extension. Like so: 1223 1224 #### Omit empty values 1225 1226 By default, a struct field is omitted when it holds the zero value (tag modifier: `omitempty`). 1227 1228 Required fields are never omitted. 1229 1230 ```go 1231 type ObjectWithTag struct { 1232 RequiredField *string `json:"requiredField"` 1233 } 1234 ``` 1235 1236 This property can be altered using the `x-omitempty` extension. Like so: 1237 ```yaml 1238 objectWithTag: 1239 type: object 1240 properties: 1241 field: 1242 type: string 1243 x-omitempty: false 1244 ``` 1245 1246 ```go 1247 type ObjectWithTag struct { 1248 Field string `json:"field"` 1249 } 1250 ``` 1251 1252 The extension does not force a required field to get the "omitempty" modifier. 1253 1254 #### Numerical values as string 1255 1256 For some specific requirements, the standard json library may consider numbers as strings. 1257 This is done by adding the modifier `json:"...,string"` to the tag. 1258 1259 With go-swagger you can specify this modifier by adding the `x-go-json-string: true` extension to your type. 1260 1261 ```go 1262 type ObjectWithTag struct { 1263 NumericField int `json:"field,omitempty,string"` 1264 } 1265 ``` 1266 1267 #### XML tags 1268 1269 The XML name and attribute Swagger properties are used to generate extra tags. 1270 ```yaml 1271 definitions: 1272 objectWithXML: 1273 type: object 1274 properties: 1275 field: 1276 type: string 1277 xml: 1278 name: xmlObject 1279 attribute: true 1280 ``` 1281 1282 ```go 1283 type ObjectWithXML struct { 1284 Field string `json:"field,omitempty" xml:"xmlObject,attr,omitempty"` 1285 } 1286 ``` 1287 1288 #### The example tag 1289 1290 If you add `example` to the list of generated tags from the CLI (`swagger generate ... --struct-tags example`), 1291 a special example tag is created with the example value taken from the specification. 1292 1293 ```yaml 1294 definitions: 1295 objectWithExample: 1296 properties: 1297 field: 1298 type: string 1299 example: "sample" 1300 ``` 1301 1302 ```go 1303 type ObjectWithExample struct { 1304 Field string `json:"field,omitempty" example:"\"sample\""` 1305 } 1306 ``` 1307 1308 #### The description tag 1309 1310 If you add `description` to the list of generated tags from the CLI (`swagger generate ... --struct-tags description`), 1311 a special description tag is created with the description value taken from the specification. 1312 1313 ```yaml 1314 definitions: 1315 objectWithDescription: 1316 properties: 1317 field: 1318 type: string 1319 description: "some description" 1320 ``` 1321 1322 ```go 1323 type ObjectWithDescription struct { 1324 Field string `json:"field,omitempty" description:"\"some description\""` 1325 } 1326 ``` 1327 1328 1329 [swagger]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#schema-object 1330 [strfmt]: https://github.com/go-openapi/strfmt 1331 [runtime]: https://github.com/go-openapi/runtime 1332 [File]: https://github.com/go-openapi/runtime/blob/master/file.go#L20 1333 [Validatable]: https://github.com/go-openapi/runtime/blob/master/interfaces.go#L101 1334 [validate]: https://github.com/go-openapi/validate 1335 [validate-json]: https://godoc.org/github.com/go-openapi/validate#ex-AgainstSchema 1336 [go-doc-model]: https://godoc.org/github.com/go-swagger/go-swagger/examples/generated/models 1337 [read-only]: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#fixed-fields-13 1338 [all-formats]: https://github.com/go-openapi/strfmt/blob/master/README.md 1339 [easy-json]: https://github.com/mailru/easyjson 1340 [json-schema]: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 1341 [lifting-pointers]: https://github.com/go-swagger/go-swagger/pull/557