Example #1
0
// Headers implements the DSL for describing HTTP headers. The DSL syntax is identical to the one
// of Attribute. Here is an example defining a couple of headers with validations:
//
//	Headers(func() {
//		Header("Authorization")
//		Header("X-Account", Integer, func() {
//			Minimum(1)
//		})
//		Required("Authorization")
//	})
//
// Headers can be used inside Action to define the action request headers, Response to define the
// response headers or Resource to define common request headers to all the resource actions.
func Headers(params ...interface{}) {
	if len(params) == 0 {
		dslengine.ReportError("missing parameter")
		return
	}
	dsl, ok := params[0].(func())
	if ok {
		switch def := dslengine.CurrentDefinition().(type) {
		case *design.ActionDefinition:
			headers := newAttribute(def.Parent.MediaType)
			if dslengine.Execute(dsl, headers) {
				def.Headers = headers
			}

		case *design.ResourceDefinition:
			headers := newAttribute(def.MediaType)
			if dslengine.Execute(dsl, headers) {
				def.Headers = headers
			}

		case *design.ResponseDefinition:
			if def.Headers != nil {
				dslengine.ReportError("headers already defined")
				return
			}
			var h *design.AttributeDefinition
			switch actual := def.Parent.(type) {
			case *design.ResourceDefinition:
				h = newAttribute(actual.MediaType)
			case *design.ActionDefinition:
				h = newAttribute(actual.Parent.MediaType)
			case nil: // API ResponseTemplate
				h = &design.AttributeDefinition{}
			default:
				dslengine.ReportError("invalid use of Response or ResponseTemplate")
			}
			if dslengine.Execute(dsl, h) {
				def.Headers = h
			}

		default:
			dslengine.IncompatibleDSL()
		}
	} else if cors, ok := corsDefinition(); ok {
		vals := make([]string, len(params))
		for i, p := range params {
			if v, ok := p.(string); ok {
				vals[i] = v
			} else {
				dslengine.ReportError("invalid parameter at position %d: must be a string", i)
				return
			}
		}
		cors.Headers = vals
	} else {
		dslengine.IncompatibleDSL()
	}
}
Example #2
0
// responseDefinition returns true and current context if it is a ResponseDefinition,
// nil and false otherwise.
func responseDefinition(failIfNotResponse bool) (*design.ResponseDefinition, bool) {
	r, ok := dslengine.CurrentDefinition().(*design.ResponseDefinition)
	if !ok && failIfNotResponse {
		dslengine.IncompatibleDSL(dslengine.Caller())
	}
	return r, ok
}
Example #3
0
// actionDefinition returns true and current context if it is an ActionDefinition,
// nil and false otherwise.
func actionDefinition(failIfNotAction bool) (*design.ActionDefinition, bool) {
	a, ok := dslengine.CurrentDefinition().(*design.ActionDefinition)
	if !ok && failIfNotAction {
		dslengine.IncompatibleDSL(dslengine.Caller())
	}
	return a, ok
}
Example #4
0
// typeDefinition returns true and current context if it is a UserTypeDefinition,
// nil and false otherwise.
func typeDefinition(failIfNotMT bool) (*design.UserTypeDefinition, bool) {
	m, ok := dslengine.CurrentDefinition().(*design.UserTypeDefinition)
	if !ok && failIfNotMT {
		dslengine.IncompatibleDSL(dslengine.Caller())
	}
	return m, ok
}
Example #5
0
// docsDefinition returns true and current context if it is a DocsDefinition,
// nil and false otherwise.
func docsDefinition(failIfNotDocs bool) (*design.DocsDefinition, bool) {
	a, ok := dslengine.CurrentDefinition().(*design.DocsDefinition)
	if !ok && failIfNotDocs {
		dslengine.IncompatibleDSL(dslengine.Caller())
	}
	return a, ok
}
Example #6
0
// licenseDefinition returns true and current context if it is an APIDefinition,
// nil and false otherwise.
func licenseDefinition(failIfNotLicense bool) (*design.LicenseDefinition, bool) {
	l, ok := dslengine.CurrentDefinition().(*design.LicenseDefinition)
	if !ok && failIfNotLicense {
		dslengine.IncompatibleDSL(dslengine.Caller())
	}
	return l, ok
}
Example #7
0
// Scope defines an authorization scope. Used within SecurityScheme, a description may be provided
// explaining what the scope means. Within a Security block, only a scope is needed.
func Scope(name string, desc ...string) {
	switch current := dslengine.CurrentDefinition().(type) {
	case *design.SecurityDefinition:
		if len(desc) >= 1 {
			dslengine.ReportError("too many arguments")
			return
		}
		current.Scopes = append(current.Scopes, name)
	case *design.SecuritySchemeDefinition:
		if len(desc) > 1 {
			dslengine.ReportError("too many arguments")
			return
		}
		if current.Scopes == nil {
			current.Scopes = make(map[string]string)
		}
		d := "no description"
		if len(desc) == 1 {
			d = desc[0]
		}
		current.Scopes[name] = d
	default:
		dslengine.IncompatibleDSL()
	}
}
Example #8
0
// buildSourceDefinition returns true and current context if it is an BuildSource
// nil and false otherwise.
func buildSourceDefinition(failIfNotSD bool) (*gorma.BuildSource, bool) {
	a, ok := dslengine.CurrentDefinition().(*gorma.BuildSource)
	if !ok && failIfNotSD {
		dslengine.IncompatibleDSL()
	}
	return a, ok
}
Example #9
0
// responseDefinition returns true and current context if it is a ResponseDefinition,
// nil and false otherwise.
func responseDefinition() (*design.ResponseDefinition, bool) {
	r, ok := dslengine.CurrentDefinition().(*design.ResponseDefinition)
	if !ok {
		dslengine.IncompatibleDSL()
	}
	return r, ok
}
Example #10
0
// Metadata is a set of key/value pairs that can be assigned to an object. Each value consists of a
// slice of strings so that multiple invocation of the Metadata function on the same target using
// the same key builds up the slice. Metadata may be set on attributes, media types, actions,
// responses, resources and API definitions.
//
// While keys can have any value the following names are handled explicitly by goagen when set on
// attributes.
//
// `struct:field:name`: overrides the Go struct field name generated by default by goagen.
// Applicable to attributes only.
//
//        Metadata("struct:field:name", "MyName")
//
// `struct:tag:xxx`: sets the struct field tag xxx on generated Go structs.  Overrides tags that
// goagen would otherwise set.  If the metadata value is a slice then the strings are joined with
// the space character as separator.
// Applicable to attributes only.
//
//        Metadata("struct:tag:json", "myName,omitempty")
//        Metadata("struct:tag:xml", "myName,attr")
//
// `swagger:generate`: specifies whether Swagger specification should be generated. Defaults to
// true.
// Applicable to resources, actions and file servers.
//
//        Metadata("swagger:generate", "false")
//
// `swagger:summary`: sets the Swagger operation summary field.
// Applicable to actions.
//
//        Metadata("swagger:summary", "Short summary of what action does")
//
// `swagger:tag:xxx`: sets the Swagger object field tag xxx.
// Applicable to resources and actions.
//
//        Metadata("swagger:tag:Backend")
//        Metadata("swagger:tag:Backend:desc", "Quick description of what 'Backend' is")
//        Metadata("swagger:tag:Backend:url", "http://example.com")
//        Metadata("swagger:tag:Backend:url:desc", "See more docs here")
//
// `swagger:extension:xxx`: sets the Swagger extensions xxx. It can have any valid JSON format value.
// Applicable to
// api as within the info and tag object,
// resource as within the paths object,
// action as within the path-item object,
// route as within the operation object,
// param as within the parameter object,
// response as within the response object
// and security as within the security-scheme object.
// See https://github.com/OAI/OpenAPI-Specification/blob/master/guidelines/EXTENSIONS.md.
//
//        Metadata("swagger:extension:x-api", `{"foo":"bar"}`)
//
// The special key names listed above may be used as follows:
//
//        var Account = Type("Account", func() {
//                Attribute("service", String, "Name of service", func() {
//                        // Override default name to avoid clash with built-in 'Service' field.
//                        Metadata("struct:field:name", "ServiceName")
//                })
//        })
//
func Metadata(name string, value ...string) {
	appendMetadata := func(metadata dslengine.MetadataDefinition, name string, value ...string) dslengine.MetadataDefinition {
		if metadata == nil {
			metadata = make(map[string][]string)
		}
		metadata[name] = append(metadata[name], value...)
		return metadata
	}

	switch def := dslengine.CurrentDefinition().(type) {
	case design.ContainerDefinition:
		att := def.Attribute()
		att.Metadata = appendMetadata(att.Metadata, name, value...)
	case *design.AttributeDefinition:
		def.Metadata = appendMetadata(def.Metadata, name, value...)
	case *design.MediaTypeDefinition:
		def.Metadata = appendMetadata(def.Metadata, name, value...)
	case *design.ActionDefinition:
		def.Metadata = appendMetadata(def.Metadata, name, value...)
	case *design.FileServerDefinition:
		def.Metadata = appendMetadata(def.Metadata, name, value...)
	case *design.ResourceDefinition:
		def.Metadata = appendMetadata(def.Metadata, name, value...)
	case *design.ResponseDefinition:
		def.Metadata = appendMetadata(def.Metadata, name, value...)
	case *design.APIDefinition:
		def.Metadata = appendMetadata(def.Metadata, name, value...)
	case *design.RouteDefinition:
		def.Metadata = appendMetadata(def.Metadata, name, value...)
	case *design.SecurityDefinition:
		def.Scheme.Metadata = appendMetadata(def.Scheme.Metadata, name, value...)
	default:
		dslengine.IncompatibleDSL()
	}
}
Example #11
0
// actionDefinition returns true and current context if it is an ActionDefinition,
// nil and false otherwise.
func actionDefinition() (*design.ActionDefinition, bool) {
	a, ok := dslengine.CurrentDefinition().(*design.ActionDefinition)
	if !ok {
		dslengine.IncompatibleDSL()
	}
	return a, ok
}
Example #12
0
// corsDefinition returns true and current context if it is a CORSDefinition, nil And
// false otherwise.
func corsDefinition() (*design.CORSDefinition, bool) {
	cors, ok := dslengine.CurrentDefinition().(*design.CORSDefinition)
	if !ok {
		dslengine.IncompatibleDSL()
	}
	return cors, ok
}
Example #13
0
// typeDefinition returns true and current context if it is a UserTypeDefinition,
// nil and false otherwise.
func typeDefinition() (*design.UserTypeDefinition, bool) {
	m, ok := dslengine.CurrentDefinition().(*design.UserTypeDefinition)
	if !ok {
		dslengine.IncompatibleDSL()
	}
	return m, ok
}
Example #14
0
// licenseDefinition returns true and current context if it is an APIDefinition,
// nil and false otherwise.
func licenseDefinition() (*design.LicenseDefinition, bool) {
	l, ok := dslengine.CurrentDefinition().(*design.LicenseDefinition)
	if !ok {
		dslengine.IncompatibleDSL()
	}
	return l, ok
}
Example #15
0
// encodingDefinition returns true and current context if it is an EncodingDefinition,
// nil and false otherwise.
func encodingDefinition(failIfNotEnc bool) (*design.EncodingDefinition, bool) {
	e, ok := dslengine.CurrentDefinition().(*design.EncodingDefinition)
	if !ok && failIfNotEnc {
		dslengine.IncompatibleDSL(dslengine.Caller())
	}
	return e, ok
}
Example #16
0
// relationalFieldDefinition returns true and current context if it is an RelationalFieldDefinition,
// nil and false otherwise.
func relationalFieldDefinition(failIfNotSD bool) (*gorma.RelationalFieldDefinition, bool) {
	a, ok := dslengine.CurrentDefinition().(*gorma.RelationalFieldDefinition)
	if !ok && failIfNotSD {
		dslengine.IncompatibleDSL()
	}
	return a, ok
}
Example #17
0
// contactDefinition returns true and current context if it is an ContactDefinition,
// nil and false otherwise.
func contactDefinition(failIfNotContact bool) (*design.ContactDefinition, bool) {
	a, ok := dslengine.CurrentDefinition().(*design.ContactDefinition)
	if !ok && failIfNotContact {
		dslengine.IncompatibleDSL(dslengine.Caller())
	}
	return a, ok
}
Example #18
0
// attributeDefinition returns true and current context if it is an AttributeDefinition
// nil and false otherwise.
func attributeDefinition(failIfNotSD bool) (*design.AttributeDefinition, bool) {
	a, ok := dslengine.CurrentDefinition().(*design.AttributeDefinition)
	if !ok && failIfNotSD {
		dslengine.IncompatibleDSL()
	}
	return a, ok
}
Example #19
0
// storageDefinition returns true and current context if it is an StorageGroupDefinition,
// nil and false otherwise.
func storageGroupDefinition(failIfNotSD bool) (*gorma.StorageGroupDefinition, bool) {
	a, ok := dslengine.CurrentDefinition().(*gorma.StorageGroupDefinition)
	if !ok && failIfNotSD {
		dslengine.IncompatibleDSL()
	}
	return a, ok
}
Example #20
0
// encodingDefinition returns true and current context if it is an EncodingDefinition,
// nil and false otherwise.
func encodingDefinition() (*design.EncodingDefinition, bool) {
	e, ok := dslengine.CurrentDefinition().(*design.EncodingDefinition)
	if !ok {
		dslengine.IncompatibleDSL()
	}
	return e, ok
}
Example #21
0
// Params describe the action parameters, either path parameters identified via wildcards or query
// string parameters if there is no corresponding path parameter. Each parameter is described via
// the Param function which uses the same DSL as the Attribute DSL. Here is an example:
//
//	Params(func() {
//		Param("id", Integer)		// A path parameter defined using e.g. GET("/:id")
//		Param("sort", String, func() {	// A query string parameter
//			Enum("asc", "desc")
//		})
//	})
//
// Params can be used inside Action to define the action parameters, Resource to define common
// parameters to all the resource actions or API to define common parameters to all the API actions.
//
// If Params is used inside Resource or Action then the resource base media type attributes provide
// default values for all the properties of params with identical names. For example:
//
//     var BottleMedia = MediaType("application/vnd.bottle", func() {
//         Attributes(func() {
//             Attribute("name", String, "The name of the bottle", func() {
//                 MinLength(2) // BottleMedia has one attribute "name" which is a
//                              // string that must be at least 2 characters long.
//             })
//         })
//         View("default", func() {
//             Attribute("name")
//         })
//     })
//
//     var _ = Resource("Bottle", func() {
//         DefaultMedia(BottleMedia) // Resource "Bottle" uses "BottleMedia" as default
//         Action("show", func() {   // media type.
//             Routing(GET("/:name"))
//             Params(func() {
//                 Param("name") // inherits type, description and validation from
//                               // BottleMedia "name" attribute
//             })
//         })
//     })
//
func Params(dsl func()) {
	var params *design.AttributeDefinition
	switch def := dslengine.CurrentDefinition().(type) {
	case *design.ActionDefinition:
		params = newAttribute(def.Parent.MediaType)
	case *design.ResourceDefinition:
		params = newAttribute(def.MediaType)
	case *design.APIDefinition:
		params = new(design.AttributeDefinition)
	default:
		dslengine.IncompatibleDSL()
	}
	params.Type = make(design.Object)
	if !dslengine.Execute(dsl, params) {
		return
	}
	switch def := dslengine.CurrentDefinition().(type) {
	case *design.ActionDefinition:
		def.Params = def.Params.Merge(params) // Useful for traits
	case *design.ResourceDefinition:
		def.Params = def.Params.Merge(params) // Useful for traits
	case *design.APIDefinition:
		def.Params = def.Params.Merge(params) // Useful for traits
	}
}
Example #22
0
File: api.go Project: smessier/goa
// UseTrait executes the API trait with the given name. UseTrait can be used inside a Resource,
// Action, Type, MediaType or Attribute DSL. UseTrait takes a variable number
// of trait names.
func UseTrait(names ...string) {
	var def dslengine.Definition

	switch typedDef := dslengine.CurrentDefinition().(type) {
	case *design.ResourceDefinition:
		def = typedDef
	case *design.ActionDefinition:
		def = typedDef
	case *design.AttributeDefinition:
		def = typedDef
	case *design.MediaTypeDefinition:
		def = typedDef
	default:
		dslengine.IncompatibleDSL()
	}

	if def != nil {
		for _, name := range names {
			if trait, ok := design.Design.Traits[name]; ok {
				dslengine.Execute(trait.DSLFunc, def)
			} else {
				dslengine.ReportError("unknown trait %s", name)
			}
		}
	}
}
Example #23
0
File: api.go Project: smessier/goa
// Origin defines the CORS policy for a given origin. The origin can use a wildcard prefix
// such as "https://*.mydomain.com". The special value "*" defines the policy for all origins
// (in which case there should be only one Origin DSL in the parent resource).
// The origin can also be a regular expression wrapped into "/".
// Example:
//
//        Origin("http://swagger.goa.design", func() { // Define CORS policy, may be prefixed with "*" wildcard
//                Headers("X-Shared-Secret")           // One or more authorized headers, use "*" to authorize all
//                Methods("GET", "POST")               // One or more authorized HTTP methods
//                Expose("X-Time")                     // One or more headers exposed to clients
//                MaxAge(600)                          // How long to cache a preflight request response
//                Credentials()                        // Sets Access-Control-Allow-Credentials header
//        })
//
//        Origin("/[api|swagger].goa.design/", func() {}) // Define CORS policy with a regular expression
func Origin(origin string, dsl func()) {
	cors := &design.CORSDefinition{Origin: origin}

	if strings.HasPrefix(origin, "/") && strings.HasSuffix(origin, "/") {
		cors.Regexp = true
		cors.Origin = strings.Trim(origin, "/")
	}

	if !dslengine.Execute(dsl, cors) {
		return
	}
	var parent dslengine.Definition
	switch def := dslengine.CurrentDefinition().(type) {
	case *design.APIDefinition:
		parent = def
		if def.Origins == nil {
			def.Origins = make(map[string]*design.CORSDefinition)
		}
		def.Origins[origin] = cors
	case *design.ResourceDefinition:
		parent = def
		if def.Origins == nil {
			def.Origins = make(map[string]*design.CORSDefinition)
		}
		def.Origins[origin] = cors
	default:
		dslengine.IncompatibleDSL()
		return
	}
	cors.Parent = parent
}
Example #24
0
// BasicAuthSecurity defines a "basic" security scheme for the API.
//
// Example:
//
//     BasicAuthSecurity("password", func() {
//         Description("Use your own password!")
//     })
//
func BasicAuthSecurity(name string, dsl ...func()) *design.SecuritySchemeDefinition {
	switch dslengine.CurrentDefinition().(type) {
	case *design.APIDefinition, *dslengine.TopLevelDefinition:
	default:
		dslengine.IncompatibleDSL()
		return nil
	}

	if securitySchemeRedefined(name) {
		return nil
	}

	def := &design.SecuritySchemeDefinition{
		Kind:       design.BasicAuthSecurityKind,
		SchemeName: name,
		Type:       "basic",
	}

	if len(dsl) != 0 {
		def.DSLFunc = dsl[0]
	}

	design.Design.SecuritySchemes = append(design.Design.SecuritySchemes, def)

	return def
}
Example #25
0
// TokenURL defines a URL to get an access token.  If you are defining OAuth2 flows, use
// `ImplicitFlow`, `PasswordFlow`, `AccessCodeFlow` or `ApplicationFlow` instead. This will set an
// endpoint where you can obtain a JWT with the JWTSecurity scheme. The URL may be a complete URL
// or just a path in which case the API scheme and host are used to build the full URL.
func TokenURL(tokenURL string) {
	if parent, ok := dslengine.CurrentDefinition().(*design.SecuritySchemeDefinition); ok {
		if parent.Kind == design.JWTSecurityKind {
			parent.TokenURL = tokenURL
			return
		}
	}
	dslengine.IncompatibleDSL()
}
Example #26
0
// NoExample sets the example of an attribute to be blank for the documentation. It is used when
// users don't want any custom or auto-generated example
func NoExample() {
	switch def := dslengine.CurrentDefinition().(type) {
	case *design.APIDefinition:
		def.NoExamples = true
	case *design.AttributeDefinition:
		def.SetExample(nil)
	default:
		dslengine.IncompatibleDSL()
	}
}
Example #27
0
File: api.go Project: smessier/goa
// Name sets the contact or license name.
func Name(name string) {
	switch def := dslengine.CurrentDefinition().(type) {
	case *design.ContactDefinition:
		def.Name = name
	case *design.LicenseDefinition:
		def.Name = name
	default:
		dslengine.IncompatibleDSL()
	}
}
Example #28
0
// TypeName makes it possible to set the Go struct name for a type or media type in the generated
// code. By default goagen uses the name (type) or identifier (media type) given in the apidsl and
// computes a valid Go identifier from it. This function makes it possible to override that and
// provide a custom name. name must be a valid Go identifier.
func TypeName(name string) {
	switch def := dslengine.CurrentDefinition().(type) {
	case *design.MediaTypeDefinition:
		def.TypeName = name
	case *design.UserTypeDefinition:
		def.TypeName = name
	default:
		dslengine.IncompatibleDSL()
	}
}
Example #29
0
// Reference sets a type or media type reference. The value itself can be a type or a media type.
// The reference type attributes define the default properties for attributes with the same name in
// the type using the reference. So for example if a type is defined as such:
//
//	var Bottle = Type("bottle", func() {
//		Attribute("name", func() {
//			MinLength(3)
//		})
//		Attribute("vintage", Integer, func() {
//			Minimum(1970)
//		})
//		Attribute("somethingelse")
//	})
//
// Declaring the following media type:
//
//	var BottleMedia = MediaType("vnd.goa.bottle", func() {
//		Reference(Bottle)
//		Attributes(func() {
//			Attribute("id", Integer)
//			Attribute("name")
//			Attribute("vintage")
//		})
//	})
//
// defines the "name" and "vintage" attributes with the same type and validations as defined in
// the Bottle type.
func Reference(t design.DataType) {
	switch def := dslengine.CurrentDefinition().(type) {
	case *design.MediaTypeDefinition:
		def.Reference = t
	case *design.AttributeDefinition:
		def.Reference = t
	default:
		dslengine.IncompatibleDSL()
	}
}
Example #30
0
// ImplicitFlow defines an "implicit" OAuth2 flow.  Use within an OAuth2Security definition.
func ImplicitFlow(authorizationURL string) {
	if parent, ok := dslengine.CurrentDefinition().(*design.SecuritySchemeDefinition); ok {
		if parent.Kind == design.OAuth2SecurityKind {
			parent.Flow = "implicit"
			parent.AuthorizationURL = authorizationURL
			return
		}
	}
	dslengine.IncompatibleDSL()
}