github.com/zak-blake/goa@v1.4.1/design/definitions.go (about)

     1  package design
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/http"
     7  	"path"
     8  	"sort"
     9  	"strings"
    10  
    11  	"github.com/dimfeld/httppath"
    12  	"github.com/goadesign/goa/dslengine"
    13  )
    14  
    15  type (
    16  	// APIDefinition defines the global properties of the API.
    17  	APIDefinition struct {
    18  		// Name of API
    19  		Name string
    20  		// Title of API
    21  		Title string
    22  		// Description of API
    23  		Description string
    24  		// Version is the version of the API described by this design.
    25  		Version string
    26  		// Host is the default API hostname
    27  		Host string
    28  		// Schemes is the supported API URL schemes
    29  		Schemes []string
    30  		// BasePath is the common base path to all API endpoints
    31  		BasePath string
    32  		// Params define the common path parameters to all API endpoints
    33  		Params *AttributeDefinition
    34  		// Consumes lists the mime types supported by the API controllers
    35  		Consumes []*EncodingDefinition
    36  		// Produces lists the mime types generated by the API controllers
    37  		Produces []*EncodingDefinition
    38  		// Origins defines the CORS policies that apply to this API.
    39  		Origins map[string]*CORSDefinition
    40  		// TermsOfService describes or links to the API terms of service
    41  		TermsOfService string
    42  		// Contact provides the API users with contact information
    43  		Contact *ContactDefinition
    44  		// License describes the API license
    45  		License *LicenseDefinition
    46  		// Docs points to the API external documentation
    47  		Docs *DocsDefinition
    48  		// Resources is the set of exposed resources indexed by name
    49  		Resources map[string]*ResourceDefinition
    50  		// Types indexes the user defined types by name
    51  		Types map[string]*UserTypeDefinition
    52  		// MediaTypes indexes the API media types by canonical identifier
    53  		MediaTypes map[string]*MediaTypeDefinition
    54  		// Traits available to all API resources and actions indexed by name
    55  		Traits map[string]*dslengine.TraitDefinition
    56  		// Responses available to all API actions indexed by name
    57  		Responses map[string]*ResponseDefinition
    58  		// Response template factories available to all API actions indexed by name
    59  		ResponseTemplates map[string]*ResponseTemplateDefinition
    60  		// Built-in responses
    61  		DefaultResponses map[string]*ResponseDefinition
    62  		// Built-in response templates
    63  		DefaultResponseTemplates map[string]*ResponseTemplateDefinition
    64  		// DSLFunc contains the DSL used to create this definition if any
    65  		DSLFunc func()
    66  		// Metadata is a list of key/value pairs
    67  		Metadata dslengine.MetadataDefinition
    68  		// SecuritySchemes lists the available security schemes available
    69  		// to the API.
    70  		SecuritySchemes []*SecuritySchemeDefinition
    71  		// Security defines security requirements for all the
    72  		// resources and actions, unless overridden by Resource or
    73  		// Action-level Security() calls.
    74  		Security *SecurityDefinition
    75  		// NoExamples indicates whether to bypass automatic example generation.
    76  		NoExamples bool
    77  
    78  		// rand is the random generator used to generate examples.
    79  		rand *RandomGenerator
    80  	}
    81  
    82  	// ContactDefinition contains the API contact information.
    83  	ContactDefinition struct {
    84  		// Name of the contact person/organization
    85  		Name string `json:"name,omitempty"`
    86  		// Email address of the contact person/organization
    87  		Email string `json:"email,omitempty"`
    88  		// URL pointing to the contact information
    89  		URL string `json:"url,omitempty"`
    90  	}
    91  
    92  	// LicenseDefinition contains the license information for the API.
    93  	LicenseDefinition struct {
    94  		// Name of license used for the API
    95  		Name string `json:"name,omitempty"`
    96  		// URL to the license used for the API
    97  		URL string `json:"url,omitempty"`
    98  	}
    99  
   100  	// DocsDefinition points to external documentation.
   101  	DocsDefinition struct {
   102  		// Description of documentation.
   103  		Description string `json:"description,omitempty"`
   104  		// URL to documentation.
   105  		URL string `json:"url,omitempty"`
   106  	}
   107  
   108  	// ResourceDefinition describes a REST resource.
   109  	// It defines both a media type and a set of actions that can be executed through HTTP
   110  	// requests.
   111  	ResourceDefinition struct {
   112  		// Resource name
   113  		Name string
   114  		// Schemes is the supported API URL schemes
   115  		Schemes []string
   116  		// Common URL prefix to all resource action HTTP requests
   117  		BasePath string
   118  		// Path and query string parameters that apply to all actions.
   119  		Params *AttributeDefinition
   120  		// Name of parent resource if any
   121  		ParentName string
   122  		// Optional description
   123  		Description string
   124  		// Default media type, describes the resource attributes
   125  		MediaType string
   126  		// Default view name if default media type is MediaTypeDefinition
   127  		DefaultViewName string
   128  		// Exposed resource actions indexed by name
   129  		Actions map[string]*ActionDefinition
   130  		// FileServers is the list of static asset serving endpoints
   131  		FileServers []*FileServerDefinition
   132  		// Action with canonical resource path
   133  		CanonicalActionName string
   134  		// Map of response definitions that apply to all actions indexed by name.
   135  		Responses map[string]*ResponseDefinition
   136  		// Request headers that apply to all actions.
   137  		Headers *AttributeDefinition
   138  		// Origins defines the CORS policies that apply to this resource.
   139  		Origins map[string]*CORSDefinition
   140  		// DSLFunc contains the DSL used to create this definition if any.
   141  		DSLFunc func()
   142  		// metadata is a list of key/value pairs
   143  		Metadata dslengine.MetadataDefinition
   144  		// Security defines security requirements for the Resource,
   145  		// for actions that don't define one themselves.
   146  		Security *SecurityDefinition
   147  	}
   148  
   149  	// CORSDefinition contains the definition for a specific origin CORS policy.
   150  	CORSDefinition struct {
   151  		// Parent API or resource
   152  		Parent dslengine.Definition
   153  		// Origin
   154  		Origin string
   155  		// List of authorized headers, "*" authorizes all
   156  		Headers []string
   157  		// List of authorized HTTP methods
   158  		Methods []string
   159  		// List of headers exposed to clients
   160  		Exposed []string
   161  		// How long to cache a prefligh request response
   162  		MaxAge uint
   163  		// Sets Access-Control-Allow-Credentials header
   164  		Credentials bool
   165  		// Sets Whether the Origin string is a regular expression
   166  		Regexp bool
   167  	}
   168  
   169  	// EncodingDefinition defines an encoder supported by the API.
   170  	EncodingDefinition struct {
   171  		// MIMETypes is the set of possible MIME types for the content being encoded or decoded.
   172  		MIMETypes []string
   173  		// PackagePath is the path to the Go package that implements the encoder/decoder.
   174  		// The package must expose a `EncoderFactory` or `DecoderFactory` function
   175  		// that the generated code calls. The methods must return objects that implement
   176  		// the goa.EncoderFactory or goa.DecoderFactory interface respectively.
   177  		PackagePath string
   178  		// Function is the name of the Go function used to instantiate the encoder/decoder.
   179  		// Defaults to NewEncoder and NewDecoder respecitively.
   180  		Function string
   181  		// Encoder is true if the definition is for a encoder, false if it's for a decoder.
   182  		Encoder bool
   183  	}
   184  
   185  	// ResponseDefinition defines a HTTP response status and optional validation rules.
   186  	ResponseDefinition struct {
   187  		// Response name
   188  		Name string
   189  		// HTTP status
   190  		Status int
   191  		// Response description
   192  		Description string
   193  		// Response body type if any
   194  		Type DataType
   195  		// Response body media type if any
   196  		MediaType string
   197  		// Response view name if MediaType is MediaTypeDefinition
   198  		ViewName string
   199  		// Response header definitions
   200  		Headers *AttributeDefinition
   201  		// Parent action or resource
   202  		Parent dslengine.Definition
   203  		// Metadata is a list of key/value pairs
   204  		Metadata dslengine.MetadataDefinition
   205  		// Standard is true if the response definition comes from the goa default responses
   206  		Standard bool
   207  	}
   208  
   209  	// ResponseTemplateDefinition defines a response template.
   210  	// A response template is a function that takes an arbitrary number
   211  	// of strings and returns a response definition.
   212  	ResponseTemplateDefinition struct {
   213  		// Response template name
   214  		Name string
   215  		// Response template function
   216  		Template func(params ...string) *ResponseDefinition
   217  	}
   218  
   219  	// ActionDefinition defines a resource action.
   220  	// It defines both an HTTP endpoint and the shape of HTTP requests and responses made to
   221  	// that endpoint.
   222  	// The shape of requests is defined via "parameters", there are path parameters
   223  	// parameters and a payload parameter (request body).
   224  	// (i.e. portions of the URL that define parameter values), query string
   225  	ActionDefinition struct {
   226  		// Action name, e.g. "create"
   227  		Name string
   228  		// Action description, e.g. "Creates a task"
   229  		Description string
   230  		// Docs points to the API external documentation
   231  		Docs *DocsDefinition
   232  		// Parent resource
   233  		Parent *ResourceDefinition
   234  		// Specific action URL schemes
   235  		Schemes []string
   236  		// Action routes
   237  		Routes []*RouteDefinition
   238  		// Map of possible response definitions indexed by name
   239  		Responses map[string]*ResponseDefinition
   240  		// Path and query string parameters
   241  		Params *AttributeDefinition
   242  		// Query string parameters only
   243  		QueryParams *AttributeDefinition
   244  		// Payload blueprint (request body) if any
   245  		Payload *UserTypeDefinition
   246  		// PayloadOptional is true if the request payload is optional, false otherwise.
   247  		PayloadOptional bool
   248  		// PayloadOptional is true if the request payload is multipart, false otherwise.
   249  		PayloadMultipart bool
   250  		// Request headers that need to be made available to action
   251  		Headers *AttributeDefinition
   252  		// Metadata is a list of key/value pairs
   253  		Metadata dslengine.MetadataDefinition
   254  		// Security defines security requirements for the action
   255  		Security *SecurityDefinition
   256  	}
   257  
   258  	// FileServerDefinition defines an endpoint that servers static assets.
   259  	FileServerDefinition struct {
   260  		// Parent resource
   261  		Parent *ResourceDefinition
   262  		// Description for docs
   263  		Description string
   264  		// Docs points to the API external documentation
   265  		Docs *DocsDefinition
   266  		// FilePath is the file path to the static asset(s)
   267  		FilePath string
   268  		// RequestPath is the HTTP path that servers the assets.
   269  		RequestPath string
   270  		// Metadata is a list of key/value pairs
   271  		Metadata dslengine.MetadataDefinition
   272  		// Security defines security requirements for the file server.
   273  		Security *SecurityDefinition
   274  	}
   275  
   276  	// LinkDefinition defines a media type link, it specifies a URL to a related resource.
   277  	LinkDefinition struct {
   278  		// Link name
   279  		Name string
   280  		// View used to render link if not "link"
   281  		View string
   282  		// URITemplate is the RFC6570 URI template of the link Href.
   283  		URITemplate string
   284  
   285  		// Parent media Type
   286  		Parent *MediaTypeDefinition
   287  	}
   288  
   289  	// ViewDefinition defines which members and links to render when building a response.
   290  	// The view is a JSON object whose property names must match the names of the parent media
   291  	// type members.
   292  	// The members fields are inherited from the parent media type but may be overridden.
   293  	ViewDefinition struct {
   294  		// Set of properties included in view
   295  		*AttributeDefinition
   296  		// Name of view
   297  		Name string
   298  		// Parent media Type
   299  		Parent *MediaTypeDefinition
   300  	}
   301  
   302  	// RouteDefinition represents an action route.
   303  	RouteDefinition struct {
   304  		// Verb is the HTTP method, e.g. "GET", "POST", etc.
   305  		Verb string
   306  		// Path is the URL path e.g. "/tasks/:id"
   307  		Path string
   308  		// Parent is the action this route applies to.
   309  		Parent *ActionDefinition
   310  		// Metadata is a list of key/value pairs
   311  		Metadata dslengine.MetadataDefinition
   312  	}
   313  
   314  	// AttributeDefinition defines a JSON object member with optional description, default
   315  	// value and validations.
   316  	AttributeDefinition struct {
   317  		// Attribute type
   318  		Type DataType
   319  		// Attribute reference type if any
   320  		Reference DataType
   321  		// Optional description
   322  		Description string
   323  		// Optional validations
   324  		Validation *dslengine.ValidationDefinition
   325  		// Metadata is a list of key/value pairs
   326  		Metadata dslengine.MetadataDefinition
   327  		// Optional member default value
   328  		DefaultValue interface{}
   329  		// Optional member example value
   330  		Example interface{}
   331  		// Optional view used to render Attribute (only applies to media type attributes).
   332  		View string
   333  		// NonZeroAttributes lists the names of the child attributes that cannot have a
   334  		// zero value (and thus whose presence does not need to be validated).
   335  		NonZeroAttributes map[string]bool
   336  		// DSLFunc contains the initialization DSL. This is used for user types.
   337  		DSLFunc func()
   338  	}
   339  
   340  	// ContainerDefinition defines a generic container definition that contains attributes.
   341  	// This makes it possible for plugins to use attributes in their own data structures.
   342  	ContainerDefinition interface {
   343  		// Attribute returns the container definition embedded attribute.
   344  		Attribute() *AttributeDefinition
   345  	}
   346  
   347  	// ResourceIterator is the type of functions given to IterateResources.
   348  	ResourceIterator func(r *ResourceDefinition) error
   349  
   350  	// MediaTypeIterator is the type of functions given to IterateMediaTypes.
   351  	MediaTypeIterator func(m *MediaTypeDefinition) error
   352  
   353  	// UserTypeIterator is the type of functions given to IterateUserTypes.
   354  	UserTypeIterator func(m *UserTypeDefinition) error
   355  
   356  	// ActionIterator is the type of functions given to IterateActions.
   357  	ActionIterator func(a *ActionDefinition) error
   358  
   359  	// FileServerIterator is the type of functions given to IterateFileServers.
   360  	FileServerIterator func(f *FileServerDefinition) error
   361  
   362  	// HeaderIterator is the type of functions given to IterateHeaders.
   363  	HeaderIterator func(name string, isRequired bool, h *AttributeDefinition) error
   364  
   365  	// ResponseIterator is the type of functions given to IterateResponses.
   366  	ResponseIterator func(r *ResponseDefinition) error
   367  )
   368  
   369  // NewAPIDefinition returns a new design with built-in response templates.
   370  func NewAPIDefinition() *APIDefinition {
   371  	api := &APIDefinition{
   372  		DefaultResponseTemplates: make(map[string]*ResponseTemplateDefinition),
   373  		DefaultResponses:         make(map[string]*ResponseDefinition),
   374  	}
   375  	t := func(params ...string) *ResponseDefinition {
   376  		if len(params) < 1 {
   377  			dslengine.ReportError("expected media type as argument when invoking response template OK")
   378  			return nil
   379  		}
   380  		return &ResponseDefinition{
   381  			Name:      OK,
   382  			Status:    200,
   383  			MediaType: params[0],
   384  		}
   385  	}
   386  	api.DefaultResponseTemplates[OK] = &ResponseTemplateDefinition{
   387  		Name:     OK,
   388  		Template: t,
   389  	}
   390  	for _, p := range []struct {
   391  		status int
   392  		name   string
   393  	}{
   394  		{100, Continue},
   395  		{101, SwitchingProtocols},
   396  		{200, OK},
   397  		{201, Created},
   398  		{202, Accepted},
   399  		{203, NonAuthoritativeInfo},
   400  		{204, NoContent},
   401  		{205, ResetContent},
   402  		{206, PartialContent},
   403  		{300, MultipleChoices},
   404  		{301, MovedPermanently},
   405  		{302, Found},
   406  		{303, SeeOther},
   407  		{304, NotModified},
   408  		{305, UseProxy},
   409  		{307, TemporaryRedirect},
   410  		{400, BadRequest},
   411  		{401, Unauthorized},
   412  		{402, PaymentRequired},
   413  		{403, Forbidden},
   414  		{404, NotFound},
   415  		{405, MethodNotAllowed},
   416  		{406, NotAcceptable},
   417  		{407, ProxyAuthRequired},
   418  		{408, RequestTimeout},
   419  		{409, Conflict},
   420  		{410, Gone},
   421  		{411, LengthRequired},
   422  		{412, PreconditionFailed},
   423  		{413, RequestEntityTooLarge},
   424  		{414, RequestURITooLong},
   425  		{415, UnsupportedMediaType},
   426  		{416, RequestedRangeNotSatisfiable},
   427  		{417, ExpectationFailed},
   428  		{418, Teapot},
   429  		{422, UnprocessableEntity},
   430  		{500, InternalServerError},
   431  		{501, NotImplemented},
   432  		{502, BadGateway},
   433  		{503, ServiceUnavailable},
   434  		{504, GatewayTimeout},
   435  		{505, HTTPVersionNotSupported},
   436  	} {
   437  		api.DefaultResponses[p.name] = &ResponseDefinition{
   438  			Name:        p.name,
   439  			Description: http.StatusText(p.status),
   440  			Status:      p.status,
   441  		}
   442  	}
   443  	return api
   444  }
   445  
   446  // DSLName is the name of the DSL as displayed to the user during execution.
   447  func (a *APIDefinition) DSLName() string {
   448  	return "goa API"
   449  }
   450  
   451  // DependsOn returns the other roots this root depends on, nothing for APIDefinition.
   452  func (a *APIDefinition) DependsOn() []dslengine.Root {
   453  	return nil
   454  }
   455  
   456  // IterateSets calls the given iterator possing in the API definition, user types, media types and
   457  // finally resources.
   458  func (a *APIDefinition) IterateSets(iterator dslengine.SetIterator) {
   459  	// First run the top level API DSL to initialize responses and
   460  	// response templates needed by resources.
   461  	iterator([]dslengine.Definition{a})
   462  
   463  	// Then run the user type DSLs
   464  	typeAttributes := make([]dslengine.Definition, len(a.Types))
   465  	i := 0
   466  	a.IterateUserTypes(func(u *UserTypeDefinition) error {
   467  		u.AttributeDefinition.DSLFunc = u.DSLFunc
   468  		typeAttributes[i] = u.AttributeDefinition
   469  		i++
   470  		return nil
   471  	})
   472  	iterator(typeAttributes)
   473  
   474  	// Then the media type DSLs
   475  	mediaTypes := make([]dslengine.Definition, len(a.MediaTypes))
   476  	i = 0
   477  	a.IterateMediaTypes(func(mt *MediaTypeDefinition) error {
   478  		mediaTypes[i] = mt
   479  		i++
   480  		return nil
   481  	})
   482  	iterator(mediaTypes)
   483  
   484  	// Then, the Security schemes definitions
   485  	var securitySchemes []dslengine.Definition
   486  	for _, scheme := range a.SecuritySchemes {
   487  		securitySchemes = append(securitySchemes, dslengine.Definition(scheme))
   488  	}
   489  	iterator(securitySchemes)
   490  
   491  	// And now that we have everything - the resources. The resource
   492  	// lifecycle handlers dispatch to their children elements, like Actions,
   493  	// etc.. We must process parent resources first to ensure that query
   494  	// string and path parameters are initialized by the time a child
   495  	// resource action parameters are categorized.
   496  	resources := make([]*ResourceDefinition, len(a.Resources))
   497  	i = 0
   498  	a.IterateResources(func(res *ResourceDefinition) error {
   499  		resources[i] = res
   500  		i++
   501  		return nil
   502  	})
   503  	sort.Sort(byParent(resources))
   504  	defs := make([]dslengine.Definition, len(resources))
   505  	for i, r := range resources {
   506  		defs[i] = r
   507  	}
   508  	iterator(defs)
   509  }
   510  
   511  // Reset sets all the API definition fields to their zero value except the default responses and
   512  // default response templates.
   513  func (a *APIDefinition) Reset() {
   514  	n := NewAPIDefinition()
   515  	*a = *n
   516  }
   517  
   518  // Context returns the generic definition name used in error messages.
   519  func (a *APIDefinition) Context() string {
   520  	if a.Name != "" {
   521  		return fmt.Sprintf("API %#v", a.Name)
   522  	}
   523  	return "unnamed API"
   524  }
   525  
   526  // PathParams returns the base path parameters of a.
   527  func (a *APIDefinition) PathParams() *AttributeDefinition {
   528  	names := ExtractWildcards(a.BasePath)
   529  	obj := make(Object)
   530  	for _, n := range names {
   531  		obj[n] = a.Params.Type.ToObject()[n]
   532  	}
   533  	return &AttributeDefinition{Type: obj}
   534  }
   535  
   536  // IterateMediaTypes calls the given iterator passing in each media type sorted in alphabetical order.
   537  // Iteration stops if an iterator returns an error and in this case IterateMediaTypes returns that
   538  // error.
   539  func (a *APIDefinition) IterateMediaTypes(it MediaTypeIterator) error {
   540  	names := make([]string, len(a.MediaTypes))
   541  	i := 0
   542  	for n := range a.MediaTypes {
   543  		names[i] = n
   544  		i++
   545  	}
   546  	sort.Strings(names)
   547  	for _, n := range names {
   548  		if err := it(a.MediaTypes[n]); err != nil {
   549  			return err
   550  		}
   551  	}
   552  	return nil
   553  }
   554  
   555  // IterateUserTypes calls the given iterator passing in each user type sorted in alphabetical order.
   556  // Iteration stops if an iterator returns an error and in this case IterateUserTypes returns that
   557  // error.
   558  func (a *APIDefinition) IterateUserTypes(it UserTypeIterator) error {
   559  	names := make([]string, len(a.Types))
   560  	i := 0
   561  	for n := range a.Types {
   562  		names[i] = n
   563  		i++
   564  	}
   565  	sort.Strings(names)
   566  	for _, n := range names {
   567  		if err := it(a.Types[n]); err != nil {
   568  			return err
   569  		}
   570  	}
   571  	return nil
   572  }
   573  
   574  // IterateResponses calls the given iterator passing in each response sorted in alphabetical order.
   575  // Iteration stops if an iterator returns an error and in this case IterateResponses returns that
   576  // error.
   577  func (a *APIDefinition) IterateResponses(it ResponseIterator) error {
   578  	names := make([]string, len(a.Responses))
   579  	i := 0
   580  	for n := range a.Responses {
   581  		names[i] = n
   582  		i++
   583  	}
   584  	sort.Strings(names)
   585  	for _, n := range names {
   586  		if err := it(a.Responses[n]); err != nil {
   587  			return err
   588  		}
   589  	}
   590  	return nil
   591  }
   592  
   593  // RandomGenerator is seeded after the API name. It's used to generate examples.
   594  func (a *APIDefinition) RandomGenerator() *RandomGenerator {
   595  	if a.rand == nil {
   596  		a.rand = NewRandomGenerator(a.Name)
   597  	}
   598  	return a.rand
   599  }
   600  
   601  // MediaTypeWithIdentifier returns the media type with a matching
   602  // media type identifier. Two media type identifiers match if their
   603  // values sans suffix match. So for example "application/vnd.foo+xml",
   604  // "application/vnd.foo+json" and "application/vnd.foo" all match.
   605  func (a *APIDefinition) MediaTypeWithIdentifier(id string) *MediaTypeDefinition {
   606  	canonicalID := CanonicalIdentifier(id)
   607  	for _, mt := range a.MediaTypes {
   608  		if canonicalID == CanonicalIdentifier(mt.Identifier) {
   609  			return mt
   610  		}
   611  	}
   612  	return nil
   613  }
   614  
   615  // IterateResources calls the given iterator passing in each resource sorted in alphabetical order.
   616  // Iteration stops if an iterator returns an error and in this case IterateResources returns that
   617  // error.
   618  func (a *APIDefinition) IterateResources(it ResourceIterator) error {
   619  	res := make([]*ResourceDefinition, len(a.Resources))
   620  	i := 0
   621  	for _, r := range a.Resources {
   622  		res[i] = r
   623  		i++
   624  	}
   625  	// Iterate parent resources first so that action parameters are
   626  	// finalized prior to child actions needing them.
   627  	isParent := func(p, c *ResourceDefinition) bool {
   628  		par := c.Parent()
   629  		for par != nil {
   630  			if par == p {
   631  				return true
   632  			}
   633  			par = par.Parent()
   634  		}
   635  		return false
   636  	}
   637  	sort.Slice(res, func(i, j int) bool {
   638  		if isParent(res[i], res[j]) {
   639  			return true
   640  		}
   641  		if isParent(res[j], res[i]) {
   642  			return false
   643  		}
   644  		return res[i].Name < res[j].Name
   645  	})
   646  	for _, r := range res {
   647  		if err := it(r); err != nil {
   648  			return err
   649  		}
   650  	}
   651  	return nil
   652  }
   653  
   654  // DSL returns the initialization DSL.
   655  func (a *APIDefinition) DSL() func() {
   656  	return a.DSLFunc
   657  }
   658  
   659  // Finalize sets the Consumes and Produces fields to the defaults if empty.
   660  // Also it records built-in media types that are used by the user design.
   661  func (a *APIDefinition) Finalize() {
   662  	if len(a.Consumes) == 0 {
   663  		a.Consumes = DefaultDecoders
   664  	}
   665  	if len(a.Produces) == 0 {
   666  		a.Produces = DefaultEncoders
   667  	}
   668  	a.IterateResources(func(r *ResourceDefinition) error {
   669  		returnsError := func(resp *ResponseDefinition) bool {
   670  			if resp.MediaType == ErrorMediaIdentifier {
   671  				if a.MediaTypes == nil {
   672  					a.MediaTypes = make(map[string]*MediaTypeDefinition)
   673  				}
   674  				a.MediaTypes[CanonicalIdentifier(ErrorMediaIdentifier)] = ErrorMedia
   675  				return true
   676  			}
   677  			return false
   678  		}
   679  		for _, resp := range a.Responses {
   680  			if returnsError(resp) {
   681  				return errors.New("done")
   682  			}
   683  		}
   684  		for _, resp := range r.Responses {
   685  			if returnsError(resp) {
   686  				return errors.New("done")
   687  			}
   688  		}
   689  		return r.IterateActions(func(action *ActionDefinition) error {
   690  			for _, resp := range action.Responses {
   691  				if returnsError(resp) {
   692  					return errors.New("done")
   693  				}
   694  			}
   695  			return nil
   696  		})
   697  	})
   698  }
   699  
   700  // NewResourceDefinition creates a resource definition but does not
   701  // execute the DSL.
   702  func NewResourceDefinition(name string, dsl func()) *ResourceDefinition {
   703  	return &ResourceDefinition{
   704  		Name:      name,
   705  		MediaType: "text/plain",
   706  		DSLFunc:   dsl,
   707  	}
   708  }
   709  
   710  // Context returns the generic definition name used in error messages.
   711  func (r *ResourceDefinition) Context() string {
   712  	if r.Name != "" {
   713  		return fmt.Sprintf("resource %#v", r.Name)
   714  	}
   715  	return "unnamed resource"
   716  }
   717  
   718  // PathParams returns the base path parameters of r.
   719  func (r *ResourceDefinition) PathParams() *AttributeDefinition {
   720  	names := ExtractWildcards(r.BasePath)
   721  	obj := make(Object)
   722  	if r.Params != nil {
   723  		for _, n := range names {
   724  			if p, ok := r.Params.Type.ToObject()[n]; ok {
   725  				obj[n] = p
   726  			}
   727  		}
   728  	}
   729  	return &AttributeDefinition{Type: obj}
   730  }
   731  
   732  // IterateActions calls the given iterator passing in each resource action sorted in alphabetical order.
   733  // Iteration stops if an iterator returns an error and in this case IterateActions returns that
   734  // error.
   735  func (r *ResourceDefinition) IterateActions(it ActionIterator) error {
   736  	names := make([]string, len(r.Actions))
   737  	i := 0
   738  	for n := range r.Actions {
   739  		names[i] = n
   740  		i++
   741  	}
   742  	sort.Strings(names)
   743  	for _, n := range names {
   744  		if err := it(r.Actions[n]); err != nil {
   745  			return err
   746  		}
   747  	}
   748  	return nil
   749  }
   750  
   751  // IterateFileServers calls the given iterator passing each resource file server sorted by file
   752  // path. Iteration stops if an iterator returns an error and in this case IterateFileServers returns
   753  // that error.
   754  func (r *ResourceDefinition) IterateFileServers(it FileServerIterator) error {
   755  	sort.Sort(ByFilePath(r.FileServers))
   756  	for _, f := range r.FileServers {
   757  		if err := it(f); err != nil {
   758  			return err
   759  		}
   760  	}
   761  	return nil
   762  }
   763  
   764  // IterateHeaders calls the given iterator passing in each response sorted in alphabetical order.
   765  // Iteration stops if an iterator returns an error and in this case IterateHeaders returns that
   766  // error.
   767  func (r *ResourceDefinition) IterateHeaders(it HeaderIterator) error {
   768  	return iterateHeaders(r.Headers, r.Headers.IsRequired, it)
   769  }
   770  
   771  // CanonicalAction returns the canonical action of the resource if any.
   772  // The canonical action is used to compute hrefs to resources.
   773  func (r *ResourceDefinition) CanonicalAction() *ActionDefinition {
   774  	name := r.CanonicalActionName
   775  	if name == "" {
   776  		name = "show"
   777  	}
   778  	ca, _ := r.Actions[name]
   779  	return ca
   780  }
   781  
   782  // URITemplate returns a URI template to this resource.
   783  // The result is the empty string if the resource does not have a "show" action
   784  // and does not define a different canonical action.
   785  func (r *ResourceDefinition) URITemplate() string {
   786  	ca := r.CanonicalAction()
   787  	if ca == nil || len(ca.Routes) == 0 {
   788  		return ""
   789  	}
   790  	return ca.Routes[0].FullPath()
   791  }
   792  
   793  // FullPath computes the base path to the resource actions concatenating the API and parent resource
   794  // base paths as needed.
   795  func (r *ResourceDefinition) FullPath() string {
   796  	if strings.HasPrefix(r.BasePath, "//") {
   797  		return httppath.Clean(r.BasePath)
   798  	}
   799  	var basePath string
   800  	if p := r.Parent(); p != nil {
   801  		if ca := p.CanonicalAction(); ca != nil {
   802  			if routes := ca.Routes; len(routes) > 0 {
   803  				// Note: all these tests should be true at code generation time
   804  				// as DSL validation makes sure that parent resources have a
   805  				// canonical path.
   806  				basePath = path.Join(routes[0].FullPath())
   807  			}
   808  		}
   809  	} else {
   810  		basePath = Design.BasePath
   811  	}
   812  	return httppath.Clean(path.Join(basePath, r.BasePath))
   813  }
   814  
   815  // Parent returns the parent resource if any, nil otherwise.
   816  func (r *ResourceDefinition) Parent() *ResourceDefinition {
   817  	if r.ParentName != "" {
   818  		if parent, ok := Design.Resources[r.ParentName]; ok {
   819  			return parent
   820  		}
   821  	}
   822  	return nil
   823  }
   824  
   825  // AllOrigins compute all CORS policies for the resource taking into account any API policy.
   826  // The result is sorted alphabetically by policy origin.
   827  func (r *ResourceDefinition) AllOrigins() []*CORSDefinition {
   828  	all := make(map[string]*CORSDefinition)
   829  	for n, o := range Design.Origins {
   830  		all[n] = o
   831  	}
   832  	for n, o := range r.Origins {
   833  		all[n] = o
   834  	}
   835  	names := make([]string, len(all))
   836  	i := 0
   837  	for n := range all {
   838  		names[i] = n
   839  		i++
   840  	}
   841  	sort.Strings(names)
   842  	cors := make([]*CORSDefinition, len(names))
   843  	for i, n := range names {
   844  		cors[i] = all[n]
   845  	}
   846  	return cors
   847  }
   848  
   849  // PreflightPaths returns the paths that should handle OPTIONS requests.
   850  func (r *ResourceDefinition) PreflightPaths() []string {
   851  	var paths []string
   852  	r.IterateActions(func(a *ActionDefinition) error {
   853  		for _, r := range a.Routes {
   854  			if r.Verb == "OPTIONS" {
   855  				continue
   856  			}
   857  			found := false
   858  			fp := r.FullPath()
   859  			for _, p := range paths {
   860  				if fp == p {
   861  					found = true
   862  					break
   863  				}
   864  			}
   865  			if !found {
   866  				paths = append(paths, fp)
   867  			}
   868  		}
   869  		return nil
   870  	})
   871  	r.IterateFileServers(func(fs *FileServerDefinition) error {
   872  		found := false
   873  		fp := fs.RequestPath
   874  		for _, p := range paths {
   875  			if fp == p {
   876  				found = true
   877  				break
   878  			}
   879  		}
   880  		if !found {
   881  			paths = append(paths, fp)
   882  		}
   883  		return nil
   884  	})
   885  	return paths
   886  }
   887  
   888  // DSL returns the initialization DSL.
   889  func (r *ResourceDefinition) DSL() func() {
   890  	return r.DSLFunc
   891  }
   892  
   893  // Finalize is run post DSL execution. It merges response definitions, creates implicit action
   894  // parameters, initializes querystring parameters, sets path parameters as non zero attributes
   895  // and sets the fallbacks for security schemes.
   896  func (r *ResourceDefinition) Finalize() {
   897  	meta := r.Metadata["swagger:generate"]
   898  	r.IterateFileServers(func(f *FileServerDefinition) error {
   899  		if meta != nil {
   900  			if _, ok := f.Metadata["swagger:generate"]; !ok {
   901  				f.Metadata["swagger:generate"] = meta
   902  			}
   903  		}
   904  		f.Finalize()
   905  		return nil
   906  	})
   907  	r.IterateActions(func(a *ActionDefinition) error {
   908  		if meta != nil {
   909  			if _, ok := a.Metadata["swagger:generate"]; !ok {
   910  				a.Metadata["swagger:generate"] = meta
   911  			}
   912  		}
   913  		a.Finalize()
   914  		return nil
   915  	})
   916  }
   917  
   918  // UserTypes returns all the user types used by the resource action payloads and parameters.
   919  func (r *ResourceDefinition) UserTypes() map[string]*UserTypeDefinition {
   920  	types := make(map[string]*UserTypeDefinition)
   921  	for _, a := range r.Actions {
   922  		for n, ut := range a.UserTypes() {
   923  			types[n] = ut
   924  		}
   925  	}
   926  	if len(types) == 0 {
   927  		return nil
   928  	}
   929  	return types
   930  }
   931  
   932  // byParent makes it possible to sort resources - parents first the children.
   933  type byParent []*ResourceDefinition
   934  
   935  func (p byParent) Len() int      { return len(p) }
   936  func (p byParent) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
   937  func (p byParent) Less(i, j int) bool {
   938  	for k := 0; k < i; k++ {
   939  		// We need to inspect _all_ previous fields to see if they are a parent. Sort doesn't do this.
   940  		if p[i].Name == p[k].ParentName {
   941  			return true
   942  		}
   943  	}
   944  
   945  	return false
   946  }
   947  
   948  // Context returns the generic definition name used in error messages.
   949  func (cors *CORSDefinition) Context() string {
   950  	return fmt.Sprintf("CORS policy for resource %s origin %s", cors.Parent.Context(), cors.Origin)
   951  }
   952  
   953  // Context returns the generic definition name used in error messages.
   954  func (enc *EncodingDefinition) Context() string {
   955  	return fmt.Sprintf("encoding for %s", strings.Join(enc.MIMETypes, ", "))
   956  }
   957  
   958  // Context returns the generic definition name used in error messages.
   959  func (a *AttributeDefinition) Context() string {
   960  	return ""
   961  }
   962  
   963  // AllRequired returns the list of all required fields from the underlying object.
   964  // An attribute type can be itself an attribute (e.g. a MediaTypeDefinition or a UserTypeDefinition)
   965  // This happens when the DSL uses references for example. So traverse the hierarchy and collect
   966  // all the required validations.
   967  func (a *AttributeDefinition) AllRequired() (required []string) {
   968  	if a == nil || a.Validation == nil {
   969  		return
   970  	}
   971  	required = a.Validation.Required
   972  	if ds, ok := a.Type.(DataStructure); ok {
   973  		required = append(required, ds.Definition().AllRequired()...)
   974  	}
   975  	return
   976  }
   977  
   978  // IsRequired returns true if the given string matches the name of a required
   979  // attribute, false otherwise.
   980  func (a *AttributeDefinition) IsRequired(attName string) bool {
   981  	for _, name := range a.AllRequired() {
   982  		if name == attName {
   983  			return true
   984  		}
   985  	}
   986  	return false
   987  }
   988  
   989  // HasDefaultValue returns true if the given attribute has a default value.
   990  func (a *AttributeDefinition) HasDefaultValue(attName string) bool {
   991  	if a.Type.IsObject() {
   992  		att := a.Type.ToObject()[attName]
   993  		return att.DefaultValue != nil
   994  	}
   995  	return false
   996  }
   997  
   998  // SetDefault sets the default for the attribute. It also converts HashVal
   999  // and ArrayVal to map and slice respectively.
  1000  func (a *AttributeDefinition) SetDefault(def interface{}) {
  1001  	switch actual := def.(type) {
  1002  	case HashVal:
  1003  		a.DefaultValue = actual.ToMap()
  1004  	case ArrayVal:
  1005  		a.DefaultValue = actual.ToSlice()
  1006  	default:
  1007  		a.DefaultValue = actual
  1008  	}
  1009  }
  1010  
  1011  // AddValues adds the Enum values to the attribute's validation definition.
  1012  // It also performs any conversion needed for HashVal and ArrayVal types.
  1013  func (a *AttributeDefinition) AddValues(values []interface{}) {
  1014  	if a.Validation == nil {
  1015  		a.Validation = &dslengine.ValidationDefinition{}
  1016  	}
  1017  	a.Validation.Values = make([]interface{}, len(values))
  1018  	for i, v := range values {
  1019  		switch actual := v.(type) {
  1020  		case HashVal:
  1021  			a.Validation.Values[i] = actual.ToMap()
  1022  		case ArrayVal:
  1023  			a.Validation.Values[i] = actual.ToSlice()
  1024  		default:
  1025  			a.Validation.Values[i] = actual
  1026  		}
  1027  	}
  1028  }
  1029  
  1030  // AllNonZero returns the complete list of all non-zero attribute name.
  1031  func (a *AttributeDefinition) AllNonZero() []string {
  1032  	nzs := make([]string, len(a.NonZeroAttributes))
  1033  	i := 0
  1034  	for n := range a.NonZeroAttributes {
  1035  		nzs[i] = n
  1036  		i++
  1037  	}
  1038  	return nzs
  1039  }
  1040  
  1041  // IsNonZero returns true if the given string matches the name of a non-zero
  1042  // attribute, false otherwise.
  1043  func (a *AttributeDefinition) IsNonZero(attName string) bool {
  1044  	return a.NonZeroAttributes[attName]
  1045  }
  1046  
  1047  // IsPrimitivePointer returns true if the field generated for the given attribute should be a
  1048  // pointer to a primitive type. The target attribute must be an object.
  1049  func (a *AttributeDefinition) IsPrimitivePointer(attName string) bool {
  1050  	if !a.Type.IsObject() {
  1051  		panic("checking pointer field on non-object") // bug
  1052  	}
  1053  	att := a.Type.ToObject()[attName]
  1054  	if att == nil {
  1055  		return false
  1056  	}
  1057  	if att.Type.IsPrimitive() {
  1058  		return (!a.IsRequired(attName) && !a.HasDefaultValue(attName) && !a.IsNonZero(attName) && !a.IsInterface(attName)) || a.IsFile(attName)
  1059  	}
  1060  	return false
  1061  }
  1062  
  1063  // IsInterface returns true if the field generated for the given attribute has
  1064  // an interface type that should not be referenced as a "*interface{}" pointer.
  1065  // The target attribute must be an object.
  1066  func (a *AttributeDefinition) IsInterface(attName string) bool {
  1067  	if !a.Type.IsObject() {
  1068  		panic("checking pointer field on non-object") // bug
  1069  	}
  1070  	att := a.Type.ToObject()[attName]
  1071  	if att == nil {
  1072  		return false
  1073  	}
  1074  	return att.Type.Kind() == AnyKind
  1075  }
  1076  
  1077  // IsFile returns true if the attribute is of type File or if any its children attributes (if any) is.
  1078  func (a *AttributeDefinition) IsFile(attName string) bool {
  1079  	if !a.Type.IsObject() {
  1080  		panic("checking pointer field on non-object") // bug
  1081  	}
  1082  	att := a.Type.ToObject()[attName]
  1083  	if att == nil {
  1084  		return false
  1085  	}
  1086  	return att.Type.Kind() == FileKind
  1087  }
  1088  
  1089  // SetExample sets the custom example. SetExample also handles the case when the user doesn't
  1090  // want any example or any auto-generated example.
  1091  func (a *AttributeDefinition) SetExample(example interface{}) bool {
  1092  	if example == nil {
  1093  		a.Example = "-" // set it to something else than nil so we know not to generate one
  1094  		return true
  1095  	}
  1096  	if a.Type == nil || a.Type.IsCompatible(example) {
  1097  		a.Example = example
  1098  		return true
  1099  	}
  1100  	return false
  1101  }
  1102  
  1103  // GenerateExample returns the value of the Example field if not nil. Otherwise it traverses the
  1104  // attribute type and recursively generates an example. The result is saved in the Example field.
  1105  func (a *AttributeDefinition) GenerateExample(rand *RandomGenerator, seen []string) interface{} {
  1106  	if a.Example != nil {
  1107  		return a.Example
  1108  	}
  1109  	if Design.NoExamples {
  1110  		return nil
  1111  	}
  1112  
  1113  	// Avoid infinite loops
  1114  	var key string
  1115  	if mt, ok := a.Type.(*MediaTypeDefinition); ok {
  1116  		key = mt.Identifier
  1117  	} else if ut, ok := a.Type.(*UserTypeDefinition); ok {
  1118  		key = ut.TypeName
  1119  	}
  1120  	if key != "" {
  1121  		count := 0
  1122  		for _, k := range seen {
  1123  			if k == key {
  1124  				count++
  1125  			}
  1126  		}
  1127  		if count > 1 {
  1128  			// Only go a couple of levels deep
  1129  			return nil
  1130  		}
  1131  		seen = append(seen, key)
  1132  	}
  1133  
  1134  	switch {
  1135  	case a.Type.IsArray():
  1136  		a.Example = a.arrayExample(rand, seen)
  1137  
  1138  	case a.Type.IsHash():
  1139  		a.Example = a.hashExample(rand, seen)
  1140  
  1141  	case a.Type.IsObject():
  1142  		a.Example = a.objectExample(rand, seen)
  1143  
  1144  	default:
  1145  		a.Example = newExampleGenerator(a, rand).Generate(seen)
  1146  	}
  1147  
  1148  	return a.Example
  1149  }
  1150  
  1151  // SetReadOnly sets the attribute's ReadOnly field as true.
  1152  func (a *AttributeDefinition) SetReadOnly() {
  1153  	if a.Metadata == nil {
  1154  		a.Metadata = map[string][]string{}
  1155  	}
  1156  	a.Metadata["swagger:read-only"] = nil
  1157  }
  1158  
  1159  // IsReadOnly returns true if attribute is read-only (set using SetReadOnly() method)
  1160  func (a *AttributeDefinition) IsReadOnly() bool {
  1161  	if _, readOnlyMetadataIsPresent := a.Metadata["swagger:read-only"]; readOnlyMetadataIsPresent {
  1162  		return true
  1163  	}
  1164  	return false
  1165  }
  1166  
  1167  func (a *AttributeDefinition) arrayExample(rand *RandomGenerator, seen []string) interface{} {
  1168  	ary := a.Type.ToArray()
  1169  	ln := newExampleGenerator(a, rand).ExampleLength()
  1170  	var res []interface{}
  1171  	for i := 0; i < ln; i++ {
  1172  		ex := ary.ElemType.GenerateExample(rand, seen)
  1173  		if ex != nil {
  1174  			res = append(res, ex)
  1175  		}
  1176  	}
  1177  	if len(res) == 0 {
  1178  		return nil
  1179  	}
  1180  	return ary.MakeSlice(res)
  1181  }
  1182  
  1183  func (a *AttributeDefinition) hashExample(rand *RandomGenerator, seen []string) interface{} {
  1184  	h := a.Type.ToHash()
  1185  	ln := newExampleGenerator(a, rand).ExampleLength()
  1186  	res := make(map[interface{}]interface{})
  1187  	for i := 0; i < ln; i++ {
  1188  		k := h.KeyType.GenerateExample(rand, seen)
  1189  		v := h.ElemType.GenerateExample(rand, seen)
  1190  		if k != nil && v != nil {
  1191  			res[k] = v
  1192  		}
  1193  	}
  1194  	if len(res) == 0 {
  1195  		return nil
  1196  	}
  1197  	return h.MakeMap(res)
  1198  }
  1199  
  1200  func (a *AttributeDefinition) objectExample(rand *RandomGenerator, seen []string) interface{} {
  1201  	// project media types
  1202  	actual := a
  1203  	if mt, ok := a.Type.(*MediaTypeDefinition); ok {
  1204  		v := a.View
  1205  		if v == "" {
  1206  			v = DefaultView
  1207  		}
  1208  		projected, _, err := mt.Project(v)
  1209  		if err != nil {
  1210  			panic(err) // bug
  1211  		}
  1212  		actual = projected.AttributeDefinition
  1213  	}
  1214  
  1215  	// ensure fixed ordering so random values are computed with consistent seeds
  1216  	aObj := actual.Type.ToObject()
  1217  	keys := make([]string, len(aObj))
  1218  	i := 0
  1219  	for n := range aObj {
  1220  		keys[i] = n
  1221  		i++
  1222  	}
  1223  	sort.Strings(keys)
  1224  
  1225  	res := make(map[string]interface{})
  1226  	for _, n := range keys {
  1227  		att := aObj[n]
  1228  		if ex := att.GenerateExample(rand, seen); ex != nil {
  1229  			res[n] = ex
  1230  		}
  1231  	}
  1232  	if len(res) > 0 {
  1233  		a.Example = res
  1234  	}
  1235  
  1236  	return a.Example
  1237  }
  1238  
  1239  // Merge merges the argument attributes into the target and returns the target overriding existing
  1240  // attributes with identical names.
  1241  // This only applies to attributes of type Object and Merge panics if the
  1242  // argument or the target is not of type Object.
  1243  func (a *AttributeDefinition) Merge(other *AttributeDefinition) *AttributeDefinition {
  1244  	if other == nil {
  1245  		return a
  1246  	}
  1247  	if a == nil {
  1248  		return other
  1249  	}
  1250  	left := a.Type.(Object)
  1251  	right := other.Type.(Object)
  1252  	if left == nil || right == nil {
  1253  		panic("cannot merge non object attributes") // bug
  1254  	}
  1255  	for n, v := range right {
  1256  		left[n] = v
  1257  	}
  1258  	if other.Validation != nil && len(other.Validation.Required) > 0 {
  1259  		if a.Validation == nil {
  1260  			a.Validation = &dslengine.ValidationDefinition{}
  1261  		}
  1262  		for _, r := range other.Validation.Required {
  1263  			a.Validation.Required = append(a.Validation.Required, r)
  1264  		}
  1265  	}
  1266  	return a
  1267  }
  1268  
  1269  // Inherit merges the properties of existing target type attributes with the argument's.
  1270  // The algorithm is recursive so that child attributes are also merged.
  1271  func (a *AttributeDefinition) Inherit(parent *AttributeDefinition, seen ...map[*AttributeDefinition]struct{}) {
  1272  	if !a.shouldInherit(parent) {
  1273  		return
  1274  	}
  1275  
  1276  	a.inheritValidations(parent)
  1277  	a.inheritRecursive(parent, seen...)
  1278  }
  1279  
  1280  // DSL returns the initialization DSL.
  1281  func (a *AttributeDefinition) DSL() func() {
  1282  	return a.DSLFunc
  1283  }
  1284  
  1285  func (a *AttributeDefinition) inheritRecursive(parent *AttributeDefinition, seen ...map[*AttributeDefinition]struct{}) {
  1286  	// prevent infinite recursions
  1287  	var s map[*AttributeDefinition]struct{}
  1288  	if len(seen) > 0 {
  1289  		s = seen[0]
  1290  		if _, ok := s[parent]; ok {
  1291  			return
  1292  		}
  1293  	} else {
  1294  		s = make(map[*AttributeDefinition]struct{})
  1295  	}
  1296  	s[parent] = struct{}{}
  1297  
  1298  	if !a.shouldInherit(parent) {
  1299  		return
  1300  	}
  1301  
  1302  	for n, att := range a.Type.ToObject() {
  1303  		if patt, ok := parent.Type.ToObject()[n]; ok {
  1304  			if att.Description == "" {
  1305  				att.Description = patt.Description
  1306  			}
  1307  			att.inheritValidations(patt)
  1308  			if att.DefaultValue == nil {
  1309  				att.DefaultValue = patt.DefaultValue
  1310  			}
  1311  			if att.View == "" {
  1312  				att.View = patt.View
  1313  			}
  1314  			if att.Type == nil {
  1315  				att.Type = patt.Type
  1316  			} else if att.shouldInherit(patt) {
  1317  				for _, att := range att.Type.ToObject() {
  1318  					att.Inherit(patt.Type.ToObject()[n], s)
  1319  				}
  1320  			}
  1321  			if att.Example == nil {
  1322  				att.Example = patt.Example
  1323  			}
  1324  			if patt.Metadata != nil {
  1325  				if att.Metadata == nil {
  1326  					att.Metadata = patt.Metadata
  1327  				} else {
  1328  					// Copy all key/value pairs from parent to child that DO NOT exist in child; existing ones will remain with the same value
  1329  					for k, v := range patt.Metadata {
  1330  						if _, keyMetadataIsPresent := att.Metadata[k]; !keyMetadataIsPresent {
  1331  							att.Metadata[k] = v
  1332  						}
  1333  					}
  1334  				}
  1335  			}
  1336  		}
  1337  	}
  1338  }
  1339  
  1340  func (a *AttributeDefinition) inheritValidations(parent *AttributeDefinition) {
  1341  	if parent.Validation == nil {
  1342  		return
  1343  	}
  1344  	if a.Validation == nil {
  1345  		a.Validation = &dslengine.ValidationDefinition{}
  1346  	}
  1347  	a.Validation.AddRequired(parent.Validation.Required)
  1348  }
  1349  
  1350  func (a *AttributeDefinition) shouldInherit(parent *AttributeDefinition) bool {
  1351  	return a != nil && a.Type.ToObject() != nil &&
  1352  		parent != nil && parent.Type.ToObject() != nil
  1353  }
  1354  
  1355  // Context returns the generic definition name used in error messages.
  1356  func (c *ContactDefinition) Context() string {
  1357  	if c.Name != "" {
  1358  		return fmt.Sprintf("contact %s", c.Name)
  1359  	}
  1360  	return "unnamed contact"
  1361  }
  1362  
  1363  // Context returns the generic definition name used in error messages.
  1364  func (l *LicenseDefinition) Context() string {
  1365  	if l.Name != "" {
  1366  		return fmt.Sprintf("license %s", l.Name)
  1367  	}
  1368  	return "unnamed license"
  1369  }
  1370  
  1371  // Context returns the generic definition name used in error messages.
  1372  func (d *DocsDefinition) Context() string {
  1373  	return fmt.Sprintf("documentation for %s", Design.Name)
  1374  }
  1375  
  1376  // Context returns the generic definition name used in error messages.
  1377  func (t *UserTypeDefinition) Context() string {
  1378  	if t.TypeName != "" {
  1379  		return fmt.Sprintf("type %#v", t.TypeName)
  1380  	}
  1381  	return "unnamed type"
  1382  }
  1383  
  1384  // DSL returns the initialization DSL.
  1385  func (t *UserTypeDefinition) DSL() func() {
  1386  	return t.DSLFunc
  1387  }
  1388  
  1389  // Context returns the generic definition name used in error messages.
  1390  func (r *ResponseDefinition) Context() string {
  1391  	var prefix, suffix string
  1392  	if r.Name != "" {
  1393  		prefix = fmt.Sprintf("response %#v", r.Name)
  1394  	} else {
  1395  		prefix = "unnamed response"
  1396  	}
  1397  	if r.Parent != nil {
  1398  		suffix = fmt.Sprintf(" of %s", r.Parent.Context())
  1399  	}
  1400  	return prefix + suffix
  1401  }
  1402  
  1403  // Finalize sets the response media type from its type if the type is a media type and no media
  1404  // type is already specified.
  1405  func (r *ResponseDefinition) Finalize() {
  1406  	if r.Type == nil {
  1407  		return
  1408  	}
  1409  	if r.MediaType != "" && r.MediaType != "text/plain" {
  1410  		return
  1411  	}
  1412  	mt, ok := r.Type.(*MediaTypeDefinition)
  1413  	if !ok {
  1414  		return
  1415  	}
  1416  	r.MediaType = mt.Identifier
  1417  }
  1418  
  1419  // Dup returns a copy of the response definition.
  1420  func (r *ResponseDefinition) Dup() *ResponseDefinition {
  1421  	res := ResponseDefinition{
  1422  		Name:        r.Name,
  1423  		Status:      r.Status,
  1424  		Description: r.Description,
  1425  		MediaType:   r.MediaType,
  1426  		ViewName:    r.ViewName,
  1427  	}
  1428  	if r.Headers != nil {
  1429  		res.Headers = DupAtt(r.Headers)
  1430  	}
  1431  	return &res
  1432  }
  1433  
  1434  // Merge merges other into target. Only the fields of target that are not already set are merged.
  1435  func (r *ResponseDefinition) Merge(other *ResponseDefinition) {
  1436  	if other == nil {
  1437  		return
  1438  	}
  1439  	if r.Name == "" {
  1440  		r.Name = other.Name
  1441  	}
  1442  	if r.Status == 0 {
  1443  		r.Status = other.Status
  1444  	}
  1445  	if r.Description == "" {
  1446  		r.Description = other.Description
  1447  	}
  1448  	if r.MediaType == "" {
  1449  		r.MediaType = other.MediaType
  1450  		r.ViewName = other.ViewName
  1451  	}
  1452  	if other.Headers != nil {
  1453  		otherHeaders := other.Headers.Type.ToObject()
  1454  		if len(otherHeaders) > 0 {
  1455  			if r.Headers == nil {
  1456  				r.Headers = &AttributeDefinition{Type: Object{}}
  1457  			}
  1458  			headers := r.Headers.Type.ToObject()
  1459  			for n, h := range otherHeaders {
  1460  				if _, ok := headers[n]; !ok {
  1461  					headers[n] = h
  1462  				}
  1463  			}
  1464  		}
  1465  	}
  1466  }
  1467  
  1468  // Context returns the generic definition name used in error messages.
  1469  func (r *ResponseTemplateDefinition) Context() string {
  1470  	if r.Name != "" {
  1471  		return fmt.Sprintf("response template %#v", r.Name)
  1472  	}
  1473  	return "unnamed response template"
  1474  }
  1475  
  1476  // Context returns the generic definition name used in error messages.
  1477  func (a *ActionDefinition) Context() string {
  1478  	var prefix, suffix string
  1479  	if a.Name != "" {
  1480  		suffix = fmt.Sprintf("action %#v", a.Name)
  1481  	} else {
  1482  		suffix = "unnamed action"
  1483  	}
  1484  	if a.Parent != nil {
  1485  		prefix = a.Parent.Context() + " "
  1486  	}
  1487  	return prefix + suffix
  1488  }
  1489  
  1490  // PathParams returns the path parameters of the action across all its routes.
  1491  func (a *ActionDefinition) PathParams() *AttributeDefinition {
  1492  	obj := make(Object)
  1493  	allParams := a.AllParams().Type.ToObject()
  1494  	for _, r := range a.Routes {
  1495  		for _, p := range r.Params() {
  1496  			if _, ok := obj[p]; !ok {
  1497  				obj[p] = allParams[p]
  1498  			}
  1499  		}
  1500  	}
  1501  	return &AttributeDefinition{Type: obj}
  1502  }
  1503  
  1504  // AllParams returns the path and query string parameters of the action across all its routes.
  1505  func (a *ActionDefinition) AllParams() *AttributeDefinition {
  1506  	var res *AttributeDefinition
  1507  	if a.Params != nil {
  1508  		res = DupAtt(a.Params)
  1509  	} else {
  1510  		res = &AttributeDefinition{Type: Object{}}
  1511  	}
  1512  	if a.HasAbsoluteRoutes() {
  1513  		return res
  1514  	}
  1515  	res = res.Merge(a.Parent.Params)
  1516  	if p := a.Parent.Parent(); p != nil {
  1517  		res = res.Merge(p.CanonicalAction().PathParams())
  1518  	} else {
  1519  		res = res.Merge(a.Parent.PathParams())
  1520  	}
  1521  	return res.Merge(Design.Params)
  1522  }
  1523  
  1524  // HasAbsoluteRoutes returns true if all the action routes are absolute.
  1525  func (a *ActionDefinition) HasAbsoluteRoutes() bool {
  1526  	for _, r := range a.Routes {
  1527  		if !r.IsAbsolute() {
  1528  			return false
  1529  		}
  1530  	}
  1531  	return true
  1532  }
  1533  
  1534  // CanonicalScheme returns the preferred scheme for making requests. Favor secure schemes.
  1535  func (a *ActionDefinition) CanonicalScheme() string {
  1536  	if a.WebSocket() {
  1537  		for _, s := range a.EffectiveSchemes() {
  1538  			if s == "wss" {
  1539  				return s
  1540  			}
  1541  		}
  1542  		return "ws"
  1543  	}
  1544  	for _, s := range a.EffectiveSchemes() {
  1545  		if s == "https" {
  1546  			return s
  1547  		}
  1548  	}
  1549  	return "http"
  1550  }
  1551  
  1552  // EffectiveSchemes return the URL schemes that apply to the action. Looks recursively into action
  1553  // resource, parent resources and API.
  1554  func (a *ActionDefinition) EffectiveSchemes() []string {
  1555  	// Compute the schemes
  1556  	schemes := a.Schemes
  1557  	if len(schemes) == 0 {
  1558  		res := a.Parent
  1559  		schemes = res.Schemes
  1560  		parent := res.Parent()
  1561  		for len(schemes) == 0 && parent != nil {
  1562  			schemes = parent.Schemes
  1563  			parent = parent.Parent()
  1564  		}
  1565  		if len(schemes) == 0 {
  1566  			schemes = Design.Schemes
  1567  		}
  1568  	}
  1569  	return schemes
  1570  }
  1571  
  1572  // WebSocket returns true if the action scheme is "ws" or "wss" or both (directly or inherited
  1573  // from the resource or API)
  1574  func (a *ActionDefinition) WebSocket() bool {
  1575  	schemes := a.EffectiveSchemes()
  1576  	if len(schemes) == 0 {
  1577  		return false
  1578  	}
  1579  	for _, s := range schemes {
  1580  		if s != "ws" && s != "wss" {
  1581  			return false
  1582  		}
  1583  	}
  1584  	return true
  1585  }
  1586  
  1587  // Finalize inherits security scheme and action responses from parent and top level design.
  1588  func (a *ActionDefinition) Finalize() {
  1589  	// Inherit security scheme
  1590  	if a.Security == nil {
  1591  		a.Security = a.Parent.Security // ResourceDefinition
  1592  		if a.Security == nil {
  1593  			a.Security = Design.Security
  1594  		}
  1595  	}
  1596  
  1597  	if a.Security != nil && a.Security.Scheme.Kind == NoSecurityKind {
  1598  		a.Security = nil
  1599  	}
  1600  
  1601  	if a.Payload != nil {
  1602  		a.Payload.Finalize()
  1603  	}
  1604  
  1605  	a.mergeResponses()
  1606  	a.initImplicitParams()
  1607  	a.initQueryParams()
  1608  }
  1609  
  1610  // UserTypes returns all the user types used by the action payload and parameters.
  1611  func (a *ActionDefinition) UserTypes() map[string]*UserTypeDefinition {
  1612  	types := make(map[string]*UserTypeDefinition)
  1613  	allp := a.AllParams().Type.ToObject()
  1614  	if a.Payload != nil {
  1615  		allp["__payload__"] = &AttributeDefinition{Type: a.Payload}
  1616  	}
  1617  	for n, ut := range UserTypes(allp) {
  1618  		types[n] = ut
  1619  	}
  1620  	for _, r := range a.Responses {
  1621  		if mt := Design.MediaTypeWithIdentifier(r.MediaType); mt != nil {
  1622  			types[mt.TypeName] = mt.UserTypeDefinition
  1623  			for n, ut := range UserTypes(mt.UserTypeDefinition) {
  1624  				types[n] = ut
  1625  			}
  1626  		}
  1627  	}
  1628  	if len(types) == 0 {
  1629  		return nil
  1630  	}
  1631  	return types
  1632  }
  1633  
  1634  // IterateHeaders iterates over the resource-level and action-level headers,
  1635  // calling the given iterator passing in each response sorted in alphabetical order.
  1636  // Iteration stops if an iterator returns an error and in this case IterateHeaders returns that
  1637  // error.
  1638  func (a *ActionDefinition) IterateHeaders(it HeaderIterator) error {
  1639  	mergedHeaders := a.Parent.Headers.Merge(a.Headers)
  1640  
  1641  	isRequired := func(name string) bool {
  1642  		// header required in either the Resource or Action scope?
  1643  		return a.Parent.Headers.IsRequired(name) || a.Headers.IsRequired(name)
  1644  	}
  1645  
  1646  	return iterateHeaders(mergedHeaders, isRequired, it)
  1647  }
  1648  
  1649  // IterateResponses calls the given iterator passing in each response sorted in alphabetical order.
  1650  // Iteration stops if an iterator returns an error and in this case IterateResponses returns that
  1651  // error.
  1652  func (a *ActionDefinition) IterateResponses(it ResponseIterator) error {
  1653  	names := make([]string, len(a.Responses))
  1654  	i := 0
  1655  	for n := range a.Responses {
  1656  		names[i] = n
  1657  		i++
  1658  	}
  1659  	sort.Strings(names)
  1660  	for _, n := range names {
  1661  		if err := it(a.Responses[n]); err != nil {
  1662  			return err
  1663  		}
  1664  	}
  1665  	return nil
  1666  }
  1667  
  1668  // mergeResponses merges the parent resource and design responses.
  1669  func (a *ActionDefinition) mergeResponses() {
  1670  	for name, resp := range a.Parent.Responses {
  1671  		if _, ok := a.Responses[name]; !ok {
  1672  			if a.Responses == nil {
  1673  				a.Responses = make(map[string]*ResponseDefinition)
  1674  			}
  1675  			a.Responses[name] = resp.Dup()
  1676  		}
  1677  	}
  1678  	for name, resp := range a.Responses {
  1679  		resp.Finalize()
  1680  		if pr, ok := a.Parent.Responses[name]; ok {
  1681  			resp.Merge(pr)
  1682  		}
  1683  		if ar, ok := Design.Responses[name]; ok {
  1684  			resp.Merge(ar)
  1685  		}
  1686  		if dr, ok := Design.DefaultResponses[name]; ok {
  1687  			resp.Merge(dr)
  1688  		}
  1689  	}
  1690  }
  1691  
  1692  // initImplicitParams creates params for path segments that don't have one.
  1693  func (a *ActionDefinition) initImplicitParams() {
  1694  	for _, ro := range a.Routes {
  1695  		for _, wc := range ro.Params() {
  1696  			found := false
  1697  			search := func(params *AttributeDefinition) {
  1698  				if params == nil {
  1699  					return
  1700  				}
  1701  				att, ok := params.Type.ToObject()[wc]
  1702  				if ok {
  1703  					if a.Params == nil {
  1704  						a.Params = &AttributeDefinition{Type: Object{}}
  1705  					}
  1706  					a.Params.Type.ToObject()[wc] = att
  1707  					found = true
  1708  				}
  1709  			}
  1710  			search(a.Params)
  1711  			parent := a.Parent
  1712  			for !found && parent != nil {
  1713  				bp := parent.Params
  1714  				parent = parent.Parent()
  1715  				search(bp)
  1716  			}
  1717  			if found {
  1718  				continue
  1719  			}
  1720  			search(Design.Params)
  1721  			if found {
  1722  				continue
  1723  			}
  1724  			if a.Params == nil {
  1725  				a.Params = &AttributeDefinition{Type: Object{}}
  1726  			}
  1727  			a.Params.Type.ToObject()[wc] = &AttributeDefinition{Type: String}
  1728  		}
  1729  	}
  1730  }
  1731  
  1732  // initQueryParams extract the query parameters from the action params.
  1733  func (a *ActionDefinition) initQueryParams() {
  1734  	// 3. Compute QueryParams from Params and set all path params as non zero attributes
  1735  	if params := a.AllParams(); params != nil {
  1736  		queryParams := DupAtt(params)
  1737  		queryParams.Type = Dup(queryParams.Type)
  1738  		if a.Params == nil {
  1739  			a.Params = &AttributeDefinition{Type: Object{}}
  1740  		}
  1741  		a.Params.NonZeroAttributes = make(map[string]bool)
  1742  		for _, route := range a.Routes {
  1743  			pnames := route.Params()
  1744  			for _, pname := range pnames {
  1745  				a.Params.NonZeroAttributes[pname] = true
  1746  				delete(queryParams.Type.ToObject(), pname)
  1747  				if queryParams.Validation != nil {
  1748  					req := queryParams.Validation.Required
  1749  					for i, n := range req {
  1750  						if n == pname {
  1751  							queryParams.Validation.Required = append(req[:i], req[i+1:]...)
  1752  							break
  1753  						}
  1754  					}
  1755  				}
  1756  			}
  1757  		}
  1758  		a.QueryParams = queryParams
  1759  	}
  1760  }
  1761  
  1762  // Context returns the generic definition name used in error messages.
  1763  func (f *FileServerDefinition) Context() string {
  1764  	suffix := fmt.Sprintf("file server %s", f.FilePath)
  1765  	var prefix string
  1766  	if f.Parent != nil {
  1767  		prefix = f.Parent.Context() + " "
  1768  	}
  1769  	return prefix + suffix
  1770  }
  1771  
  1772  // Finalize inherits security scheme from parent and top level design.
  1773  func (f *FileServerDefinition) Finalize() {
  1774  	// Make sure request path starts with a "/" so codegen can rely on it.
  1775  	if !strings.HasPrefix(f.RequestPath, "/") {
  1776  		f.RequestPath = "/" + f.RequestPath
  1777  	}
  1778  	// Inherit security
  1779  	if f.Security == nil {
  1780  		f.Security = f.Parent.Security // ResourceDefinition
  1781  		if f.Security == nil {
  1782  			f.Security = Design.Security
  1783  		}
  1784  	}
  1785  	if f.Security != nil && f.Security.Scheme.Kind == NoSecurityKind {
  1786  		f.Security = nil
  1787  	}
  1788  }
  1789  
  1790  // IsDir returns true if the file server serves a directory, false otherwise.
  1791  func (f *FileServerDefinition) IsDir() bool {
  1792  	return WildcardRegex.MatchString(f.RequestPath)
  1793  }
  1794  
  1795  // ByFilePath makes FileServerDefinition sortable for code generators.
  1796  type ByFilePath []*FileServerDefinition
  1797  
  1798  func (b ByFilePath) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
  1799  func (b ByFilePath) Len() int           { return len(b) }
  1800  func (b ByFilePath) Less(i, j int) bool { return b[i].FilePath < b[j].FilePath }
  1801  
  1802  // Context returns the generic definition name used in error messages.
  1803  func (l *LinkDefinition) Context() string {
  1804  	var prefix, suffix string
  1805  	if l.Name != "" {
  1806  		prefix = fmt.Sprintf("link %#v", l.Name)
  1807  	} else {
  1808  		prefix = "unnamed link"
  1809  	}
  1810  	if l.Parent != nil {
  1811  		suffix = fmt.Sprintf(" of %s", l.Parent.Context())
  1812  	}
  1813  	return prefix + suffix
  1814  }
  1815  
  1816  // Attribute returns the linked attribute.
  1817  func (l *LinkDefinition) Attribute() *AttributeDefinition {
  1818  	p := l.Parent.ToObject()
  1819  	if p == nil {
  1820  		return nil
  1821  	}
  1822  	att, _ := p[l.Name]
  1823  
  1824  	return att
  1825  }
  1826  
  1827  // MediaType returns the media type of the linked attribute.
  1828  func (l *LinkDefinition) MediaType() *MediaTypeDefinition {
  1829  	att := l.Attribute()
  1830  	mt, _ := att.Type.(*MediaTypeDefinition)
  1831  	return mt
  1832  }
  1833  
  1834  // Context returns the generic definition name used in error messages.
  1835  func (v *ViewDefinition) Context() string {
  1836  	var prefix, suffix string
  1837  	if v.Name != "" {
  1838  		prefix = fmt.Sprintf("view %#v", v.Name)
  1839  	} else {
  1840  		prefix = "unnamed view"
  1841  	}
  1842  	if v.Parent != nil {
  1843  		suffix = fmt.Sprintf(" of %s", v.Parent.Context())
  1844  	}
  1845  	return prefix + suffix
  1846  }
  1847  
  1848  // Context returns the generic definition name used in error messages.
  1849  func (r *RouteDefinition) Context() string {
  1850  	return fmt.Sprintf(`route %s "%s" of %s`, r.Verb, r.Path, r.Parent.Context())
  1851  }
  1852  
  1853  // Params returns the route parameters.
  1854  // For example for the route "GET /foo/:fooID" Params returns []string{"fooID"}.
  1855  func (r *RouteDefinition) Params() []string {
  1856  	return ExtractWildcards(r.FullPath())
  1857  }
  1858  
  1859  // FullPath returns the action full path computed by concatenating the API and resource base paths
  1860  // with the action specific path.
  1861  func (r *RouteDefinition) FullPath() string {
  1862  	if r.IsAbsolute() {
  1863  		return httppath.Clean(r.Path[1:])
  1864  	}
  1865  	var base string
  1866  	if r.Parent != nil && r.Parent.Parent != nil {
  1867  		base = r.Parent.Parent.FullPath()
  1868  	}
  1869  
  1870  	joinedPath := path.Join(base, r.Path)
  1871  	if strings.HasSuffix(r.Path, "/") {
  1872  		//add slash removed by Join back again (it may be important for routing)
  1873  		joinedPath += "/"
  1874  	}
  1875  
  1876  	return httppath.Clean(joinedPath)
  1877  }
  1878  
  1879  // IsAbsolute returns true if the action path should not be concatenated to the resource and API
  1880  // base paths.
  1881  func (r *RouteDefinition) IsAbsolute() bool {
  1882  	return strings.HasPrefix(r.Path, "//")
  1883  }
  1884  
  1885  func iterateHeaders(headers *AttributeDefinition, isRequired func(name string) bool, it HeaderIterator) error {
  1886  	if headers == nil || !headers.Type.IsObject() {
  1887  		return nil
  1888  	}
  1889  	headersMap := headers.Type.ToObject()
  1890  	names := make([]string, len(headersMap))
  1891  	i := 0
  1892  	for n := range headersMap {
  1893  		names[i] = n
  1894  		i++
  1895  	}
  1896  	sort.Strings(names)
  1897  	for _, n := range names {
  1898  		header := headersMap[n]
  1899  		if err := it(n, isRequired(n), header); err != nil {
  1900  			return err
  1901  		}
  1902  	}
  1903  	return nil
  1904  }