github.com/6543-forks/go-swagger@v0.26.0/generator/structs.go (about) 1 package generator 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "sort" 8 "strconv" 9 "strings" 10 11 "github.com/go-openapi/spec" 12 ) 13 14 // GenCommon contains common properties needed across 15 // definitions, app and operations 16 // TargetImportPath may be used by templates to import other (possibly 17 // generated) packages in the generation path (e.g. relative to GOPATH). 18 // TargetImportPath is NOT used by standard templates. 19 type GenCommon struct { 20 Copyright string 21 TargetImportPath string 22 } 23 24 // GenDefinition contains all the properties to generate a 25 // definition from a swagger spec 26 type GenDefinition struct { 27 GenCommon 28 GenSchema 29 Package string 30 Imports map[string]string 31 DefaultImports map[string]string 32 ExtraSchemas GenSchemaList 33 DependsOn []string 34 External bool 35 } 36 37 // GenDefinitions represents a list of operations to generate 38 // this implements a sort by operation id 39 type GenDefinitions []GenDefinition 40 41 func (g GenDefinitions) Len() int { return len(g) } 42 func (g GenDefinitions) Less(i, j int) bool { return g[i].Name < g[j].Name } 43 func (g GenDefinitions) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 44 45 // GenSchemaList is a list of schemas for generation. 46 // 47 // It can be sorted by name to get a stable struct layout for 48 // version control and such 49 type GenSchemaList []GenSchema 50 51 // GenSchema contains all the information needed to generate the code 52 // for a schema 53 type GenSchema struct { 54 resolvedType 55 sharedValidations 56 Example string 57 OriginalName string 58 Name string 59 Suffix string 60 Path string 61 ValueExpression string 62 IndexVar string 63 KeyVar string 64 Title string 65 Description string 66 Location string 67 ReceiverName string 68 Items *GenSchema 69 AllowsAdditionalItems bool 70 HasAdditionalItems bool 71 AdditionalItems *GenSchema 72 Object *GenSchema 73 XMLName string 74 CustomTag string 75 Properties GenSchemaList 76 AllOf GenSchemaList 77 HasAdditionalProperties bool 78 IsAdditionalProperties bool 79 AdditionalProperties *GenSchema 80 StrictAdditionalProperties bool 81 ReadOnly bool 82 IsVirtual bool 83 IsBaseType bool 84 HasBaseType bool 85 IsSubType bool 86 IsExported bool 87 DiscriminatorField string 88 DiscriminatorValue string 89 Discriminates map[string]string 90 Parents []string 91 IncludeValidator bool 92 IncludeModel bool 93 Default interface{} 94 WantsMarshalBinary bool // do we generate MarshalBinary interface? 95 StructTags []string 96 ExtraImports map[string]string // non-standard imports detected when using external types 97 } 98 99 func (g GenSchemaList) Len() int { return len(g) } 100 func (g GenSchemaList) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 101 func (g GenSchemaList) Less(i, j int) bool { 102 a, okA := g[i].Extensions[xOrder].(float64) 103 b, okB := g[j].Extensions[xOrder].(float64) 104 105 // If both properties have x-order defined, then the one with lower x-order is smaller 106 if okA && okB { 107 return a < b 108 } 109 110 // If only the first property has x-order defined, then it is smaller 111 if okA { 112 return true 113 } 114 115 // If only the second property has x-order defined, then it is smaller 116 if okB { 117 return false 118 } 119 120 // If neither property has x-order defined, then the one with lower lexicographic name is smaller 121 return g[i].Name < g[j].Name 122 } 123 124 type sharedValidations struct { 125 HasValidations bool 126 Required bool 127 128 // String validations 129 MaxLength *int64 130 MinLength *int64 131 Pattern string 132 133 // Number validations 134 MultipleOf *float64 135 Minimum *float64 136 Maximum *float64 137 ExclusiveMinimum bool 138 ExclusiveMaximum bool 139 140 Enum []interface{} 141 ItemsEnum []interface{} 142 143 // Slice validations 144 MinItems *int64 145 MaxItems *int64 146 UniqueItems bool 147 HasSliceValidations bool 148 149 // Not used yet (perhaps intended for maxProperties, minProperties validations?) 150 NeedsSize bool 151 152 // NOTE: "patternProperties" and "dependencies" not supported by Swagger 2.0 153 } 154 155 // GenResponse represents a response object for code generation 156 type GenResponse struct { 157 Package string 158 ModelsPackage string 159 ReceiverName string 160 Name string 161 Description string 162 163 IsSuccess bool 164 165 Code int 166 Method string 167 Path string 168 Headers GenHeaders 169 Schema *GenSchema 170 AllowsForStreaming bool 171 172 Imports map[string]string 173 DefaultImports map[string]string 174 175 Extensions map[string]interface{} 176 177 StrictResponders bool 178 OperationName string 179 } 180 181 // GenHeader represents a header on a response for code generation 182 type GenHeader struct { 183 resolvedType 184 sharedValidations 185 186 Package string 187 ReceiverName string 188 IndexVar string 189 190 ID string 191 Name string 192 Path string 193 ValueExpression string 194 195 Title string 196 Description string 197 Default interface{} 198 HasDefault bool 199 200 CollectionFormat string 201 202 Child *GenItems 203 Parent *GenItems 204 205 Converter string 206 Formatter string 207 208 ZeroValue string 209 } 210 211 // ItemsDepth returns a string "items.items..." with as many items as the level of nesting of the array. 212 // For a header objects it always returns "". 213 func (g *GenHeader) ItemsDepth() string { 214 // NOTE: this is currently used by templates to generate explicit comments in nested structures 215 return "" 216 } 217 218 // GenHeaders is a sorted collection of headers for codegen 219 type GenHeaders []GenHeader 220 221 func (g GenHeaders) Len() int { return len(g) } 222 func (g GenHeaders) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 223 func (g GenHeaders) Less(i, j int) bool { return g[i].Name < g[j].Name } 224 225 // HasSomeDefaults returns true is at least one header has a default value set 226 func (g GenHeaders) HasSomeDefaults() bool { 227 // NOTE: this is currently used by templates to avoid empty constructs 228 for _, header := range g { 229 if header.HasDefault { 230 return true 231 } 232 } 233 return false 234 } 235 236 // GenParameter is used to represent 237 // a parameter or a header for code generation. 238 type GenParameter struct { 239 resolvedType 240 sharedValidations 241 242 ID string 243 Name string 244 ModelsPackage string 245 Path string 246 ValueExpression string 247 IndexVar string 248 KeyVar string 249 ReceiverName string 250 Location string 251 Title string 252 Description string 253 Converter string 254 Formatter string 255 256 Schema *GenSchema 257 258 CollectionFormat string 259 260 Child *GenItems 261 Parent *GenItems 262 263 /// Unused 264 //BodyParam *GenParameter 265 266 Default interface{} 267 HasDefault bool 268 ZeroValue string 269 AllowEmptyValue bool 270 271 // validation strategy for Body params, which may mix model and simple constructs. 272 // Distinguish the following cases: 273 // - HasSimpleBodyParams: body is an inline simple type 274 // - HasModelBodyParams: body is a model objectd 275 // - HasSimpleBodyItems: body is an inline array of simple type 276 // - HasModelBodyItems: body is an array of model objects 277 // - HasSimpleBodyMap: body is a map of simple objects (possibly arrays) 278 // - HasModelBodyMap: body is a map of model objects 279 HasSimpleBodyParams bool 280 HasModelBodyParams bool 281 HasSimpleBodyItems bool 282 HasModelBodyItems bool 283 HasSimpleBodyMap bool 284 HasModelBodyMap bool 285 286 Extensions map[string]interface{} 287 } 288 289 // IsQueryParam returns true when this parameter is a query param 290 func (g *GenParameter) IsQueryParam() bool { 291 return g.Location == "query" 292 } 293 294 // IsPathParam returns true when this parameter is a path param 295 func (g *GenParameter) IsPathParam() bool { 296 return g.Location == "path" 297 } 298 299 // IsFormParam returns true when this parameter is a form param 300 func (g *GenParameter) IsFormParam() bool { 301 return g.Location == "formData" 302 } 303 304 // IsHeaderParam returns true when this parameter is a header param 305 func (g *GenParameter) IsHeaderParam() bool { 306 return g.Location == "header" 307 } 308 309 // IsBodyParam returns true when this parameter is a body param 310 func (g *GenParameter) IsBodyParam() bool { 311 return g.Location == "body" 312 } 313 314 // IsFileParam returns true when this parameter is a file param 315 func (g *GenParameter) IsFileParam() bool { 316 return g.SwaggerType == "file" 317 } 318 319 // ItemsDepth returns a string "items.items..." with as many items as the level of nesting of the array. 320 // For a parameter object, it always returns "". 321 func (g *GenParameter) ItemsDepth() string { 322 // NOTE: this is currently used by templates to generate explicit comments in nested structures 323 return "" 324 } 325 326 // GenParameters represents a sorted parameter collection 327 type GenParameters []GenParameter 328 329 func (g GenParameters) Len() int { return len(g) } 330 func (g GenParameters) Less(i, j int) bool { return g[i].Name < g[j].Name } 331 func (g GenParameters) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 332 333 // HasSomeDefaults returns true is at least one parameter has a default value set 334 func (g GenParameters) HasSomeDefaults() bool { 335 // NOTE: this is currently used by templates to avoid empty constructs 336 for _, param := range g { 337 if param.HasDefault { 338 return true 339 } 340 } 341 return false 342 } 343 344 // GenItems represents the collection items for a collection parameter 345 type GenItems struct { 346 sharedValidations 347 resolvedType 348 349 Name string 350 Path string 351 ValueExpression string 352 CollectionFormat string 353 Child *GenItems 354 Parent *GenItems 355 Converter string 356 Formatter string 357 358 Location string 359 IndexVar string 360 KeyVar string 361 362 // instructs generator to skip the splitting and parsing from CollectionFormat 363 SkipParse bool 364 // instructs generator that some nested structure needs an higher level loop index 365 NeedsIndex bool 366 } 367 368 // ItemsDepth returns a string "items.items..." with as many items as the level of nesting of the array. 369 func (g *GenItems) ItemsDepth() string { 370 // NOTE: this is currently used by templates to generate explicit comments in nested structures 371 current := g 372 i := 1 373 for current.Parent != nil { 374 i++ 375 current = current.Parent 376 } 377 return strings.Repeat("items.", i) 378 } 379 380 // GenOperationGroup represents a named (tagged) group of operations 381 type GenOperationGroup struct { 382 GenCommon 383 Name string 384 Operations GenOperations 385 386 Summary string 387 Description string 388 Imports map[string]string 389 DefaultImports map[string]string 390 RootPackage string 391 GenOpts *GenOpts 392 PackageAlias string 393 } 394 395 // GenOperationGroups is a sorted collection of operation groups 396 type GenOperationGroups []GenOperationGroup 397 398 func (g GenOperationGroups) Len() int { return len(g) } 399 func (g GenOperationGroups) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 400 func (g GenOperationGroups) Less(i, j int) bool { return g[i].Name < g[j].Name } 401 402 // GenStatusCodeResponses a container for status code responses 403 type GenStatusCodeResponses []GenResponse 404 405 func (g GenStatusCodeResponses) Len() int { return len(g) } 406 func (g GenStatusCodeResponses) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 407 func (g GenStatusCodeResponses) Less(i, j int) bool { return g[i].Code < g[j].Code } 408 409 // MarshalJSON marshals these responses to json 410 // 411 // This is used by DumpData. 412 func (g GenStatusCodeResponses) MarshalJSON() ([]byte, error) { 413 if g == nil { 414 return nil, nil 415 } 416 responses := make(GenStatusCodeResponses, len(g)) 417 copy(responses, g) 418 // order marshalled output 419 sort.Sort(responses) 420 421 var buf bytes.Buffer 422 buf.WriteRune('{') 423 for i, v := range responses { 424 rb, err := json.Marshal(v) 425 if err != nil { 426 return nil, err 427 } 428 if i > 0 { 429 buf.WriteRune(',') 430 } 431 buf.WriteString(fmt.Sprintf("%q:", strconv.Itoa(v.Code))) 432 buf.Write(rb) 433 } 434 buf.WriteRune('}') 435 return buf.Bytes(), nil 436 } 437 438 // UnmarshalJSON unmarshals this GenStatusCodeResponses from json 439 func (g *GenStatusCodeResponses) UnmarshalJSON(data []byte) error { 440 var dd map[string]GenResponse 441 if err := json.Unmarshal(data, &dd); err != nil { 442 return err 443 } 444 var gg GenStatusCodeResponses 445 for _, v := range dd { 446 gg = append(gg, v) 447 } 448 sort.Sort(gg) 449 *g = gg 450 return nil 451 } 452 453 // GenOperation represents an operation for code generation 454 type GenOperation struct { 455 GenCommon 456 Package string 457 ReceiverName string 458 Name string 459 Summary string 460 Description string 461 Method string 462 Path string 463 BasePath string 464 Tags []string 465 UseTags bool 466 RootPackage string 467 468 Imports map[string]string 469 DefaultImports map[string]string 470 ExtraSchemas GenSchemaList 471 PackageAlias string 472 473 Authorized bool 474 Security []GenSecurityRequirements 475 SecurityDefinitions GenSecuritySchemes 476 Principal string 477 478 SuccessResponse *GenResponse 479 SuccessResponses []GenResponse 480 Responses GenStatusCodeResponses 481 DefaultResponse *GenResponse 482 483 Params GenParameters 484 QueryParams GenParameters 485 PathParams GenParameters 486 HeaderParams GenParameters 487 FormParams GenParameters 488 HasQueryParams bool 489 HasPathParams bool 490 HasHeaderParams bool 491 HasFormParams bool 492 HasFormValueParams bool 493 HasFileParams bool 494 HasBodyParams bool 495 HasStreamingResponse bool 496 497 Schemes []string 498 ExtraSchemes []string 499 ProducesMediaTypes []string 500 ConsumesMediaTypes []string 501 TimeoutName string 502 503 Extensions map[string]interface{} 504 505 StrictResponders bool 506 } 507 508 // GenOperations represents a list of operations to generate 509 // this implements a sort by operation id 510 type GenOperations []GenOperation 511 512 func (g GenOperations) Len() int { return len(g) } 513 func (g GenOperations) Less(i, j int) bool { return g[i].Name < g[j].Name } 514 func (g GenOperations) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 515 516 // GenApp represents all the meta data needed to generate an application 517 // from a swagger spec 518 type GenApp struct { 519 GenCommon 520 APIPackage string 521 Package string 522 ReceiverName string 523 Name string 524 Principal string 525 DefaultConsumes string 526 DefaultProduces string 527 Host string 528 BasePath string 529 Info *spec.Info 530 ExternalDocs *spec.ExternalDocumentation 531 Imports map[string]string 532 DefaultImports map[string]string 533 Schemes []string 534 ExtraSchemes []string 535 Consumes GenSerGroups 536 Produces GenSerGroups 537 SecurityDefinitions GenSecuritySchemes 538 Models []GenDefinition 539 Operations GenOperations 540 OperationGroups GenOperationGroups 541 SwaggerJSON string 542 // Embedded specs: this is important for when the generated server adds routes. 543 // NOTE: there is a distinct advantage to having this in runtime rather than generated code. 544 // We are not ever going to generate the router. 545 // If embedding spec is an issue (e.g. memory usage), this can be excluded with the --exclude-spec 546 // generation option. Alternative methods to serve spec (e.g. from disk, ...) may be implemented by 547 // adding a middleware to the generated API. 548 FlatSwaggerJSON string 549 ExcludeSpec bool 550 GenOpts *GenOpts 551 } 552 553 // UseGoStructFlags returns true when no strategy is specified or it is set to "go-flags" 554 func (g *GenApp) UseGoStructFlags() bool { 555 if g.GenOpts == nil { 556 return true 557 } 558 return g.GenOpts.FlagStrategy == "" || g.GenOpts.FlagStrategy == "go-flags" 559 } 560 561 // UsePFlags returns true when the flag strategy is set to pflag 562 func (g *GenApp) UsePFlags() bool { 563 return g.GenOpts != nil && strings.HasPrefix(g.GenOpts.FlagStrategy, "pflag") 564 } 565 566 // UseFlags returns true when the flag strategy is set to flag 567 func (g *GenApp) UseFlags() bool { 568 return g.GenOpts != nil && strings.HasPrefix(g.GenOpts.FlagStrategy, "flag") 569 } 570 571 // UseIntermediateMode for https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29 572 func (g *GenApp) UseIntermediateMode() bool { 573 return g.GenOpts != nil && g.GenOpts.CompatibilityMode == "intermediate" 574 } 575 576 // UseModernMode for https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility 577 func (g *GenApp) UseModernMode() bool { 578 return g.GenOpts == nil || g.GenOpts.CompatibilityMode == "" || g.GenOpts.CompatibilityMode == "modern" 579 } 580 581 // GenSerGroups sorted representation of serializer groups 582 type GenSerGroups []GenSerGroup 583 584 func (g GenSerGroups) Len() int { return len(g) } 585 func (g GenSerGroups) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 586 func (g GenSerGroups) Less(i, j int) bool { return g[i].Name < g[j].Name } 587 588 // GenSerGroup represents a group of serializers: this links a serializer to a list of 589 // prioritized media types (mime). 590 type GenSerGroup struct { 591 GenSerializer 592 593 // All media types for this serializer. The redundant representation allows for easier use in templates 594 AllSerializers GenSerializers 595 } 596 597 // GenSerializers sorted representation of serializers 598 type GenSerializers []GenSerializer 599 600 func (g GenSerializers) Len() int { return len(g) } 601 func (g GenSerializers) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 602 func (g GenSerializers) Less(i, j int) bool { return g[i].MediaType < g[j].MediaType } 603 604 // GenSerializer represents a single serializer for a particular media type 605 type GenSerializer struct { 606 AppName string // Application name 607 ReceiverName string 608 Name string // Name of the Producer/Consumer (e.g. json, yaml, txt, bin) 609 MediaType string // mime 610 Implementation string // func implementing the Producer/Consumer 611 Parameters []string // parameters supported by this serializer 612 } 613 614 // GenSecurityScheme represents a security scheme for code generation 615 type GenSecurityScheme struct { 616 AppName string 617 ID string 618 Name string 619 ReceiverName string 620 IsBasicAuth bool 621 IsAPIKeyAuth bool 622 IsOAuth2 bool 623 Scopes []string 624 Source string 625 Principal string 626 // from spec.SecurityScheme 627 Description string 628 Type string 629 In string 630 Flow string 631 AuthorizationURL string 632 TokenURL string 633 Extensions map[string]interface{} 634 } 635 636 // GenSecuritySchemes sorted representation of serializers 637 type GenSecuritySchemes []GenSecurityScheme 638 639 func (g GenSecuritySchemes) Len() int { return len(g) } 640 func (g GenSecuritySchemes) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 641 func (g GenSecuritySchemes) Less(i, j int) bool { return g[i].ID < g[j].ID } 642 643 // GenSecurityRequirement represents a security requirement for an operation 644 type GenSecurityRequirement struct { 645 Name string 646 Scopes []string 647 } 648 649 // GenSecurityRequirements represents a compounded security requirement specification. 650 // In a []GenSecurityRequirements complete requirements specification, 651 // outer elements are interpreted as optional requirements (OR), and 652 // inner elements are interpreted as jointly required (AND). 653 type GenSecurityRequirements []GenSecurityRequirement 654 655 func (g GenSecurityRequirements) Len() int { return len(g) } 656 func (g GenSecurityRequirements) Swap(i, j int) { g[i], g[j] = g[j], g[i] } 657 func (g GenSecurityRequirements) Less(i, j int) bool { return g[i].Name < g[j].Name }