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 }