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