github.com/brycereitano/goa@v0.0.0-20170315073847-8ffa6c85e265/design/definitions.go (about)

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