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