Exemple #1
0
// Attribute implements the attribute definition DSL. An attribute describes a data structure
// recursively. Attributes are used for describing request headers, parameters and payloads -
// response bodies and headers - media types and types. An attribute definition is recursive:
// attributes may include other attributes. At the basic level an attribute has a name,
// a type and optionally a default value and validation rules. The type of an attribute can be one of:
//
// * The primitive types Boolean, Integer, Number or String.
//
// * A type defined via the Type function.
//
// * A media type defined via the MediaType function.
//
// * An object described recursively with child attributes.
//
// * An array defined using the ArrayOf function.
//
// * An hashmap defined using the HashOf function.
//
// Attributes can be defined using the Attribute, Param, Member or Header functions depending
// on where the definition appears. The syntax for all these DSL is the same.
// Here are some examples:
//
//	Attribute("name")					// Defines an attribute of type String
//
//	Attribute("name", func() {
//		Pattern("^foo")					// Adds a validation rule to the attribute
//	})
//
//	Attribute("name", Integer)				// Defines an attribute of type Integer
//
//	Attribute("name", Integer, func() {
//		Default(42)					// With a default value
//	})
//
//	Attribute("name", Integer, "description")		// Specifies a description
//
//	Attribute("name", Integer, "description", func() {
//		Enum(1, 2)					// And validation rules
//	})
//
// Nested attributes:
//
//	Attribute("nested", func() {
//		Description("description")
//		Attribute("child")
//		Attribute("child2", func() {
//			// ....
//		})
//		Required("child")
//	})
//
// Here are all the valid usage of the Attribute function:
//
//	Attribute(name string, dataType DataType, description string, dsl func())
//
//	Attribute(name string, dataType DataType, description string)
//
//	Attribute(name string, dataType DataType, dsl func())
//
//	Attribute(name string, dataType DataType)
//
//	Attribute(name string, dsl func())	// dataType is String or Object (if DSL defines child attributes)
//
//	Attribute(name string)			// dataType is String
func Attribute(name string, args ...interface{}) {
	var parent *design.AttributeDefinition
	if at, ok := attributeDefinition(false); ok {
		parent = at
	} else if mt, ok := mediaTypeDefinition(true); ok {
		parent = mt.AttributeDefinition
	}

	if parent != nil {
		if parent.Type == nil {
			parent.Type = design.Object{}
		}
		if _, ok := parent.Type.(design.Object); !ok {
			ReportError("can't define child attributes on attribute of type %s", parent.Type.Name())
			return
		}

		var baseAttr *design.AttributeDefinition
		if parent.Reference != nil {
			if att, ok := parent.Reference.ToObject()[name]; ok {
				baseAttr = att.Dup()
			}
		}

		dataType, description, dsl := parseAttributeArgs(baseAttr, args...)
		if baseAttr != nil {
			if description != "" {
				baseAttr.Description = description
			}
			if dataType != nil {
				baseAttr.Type = dataType
			}
		} else {
			baseAttr = &design.AttributeDefinition{
				Type:        dataType,
				Description: description,
			}
		}
		baseAttr.Reference = parent.Reference
		if dsl != nil {
			executeDSL(dsl, baseAttr)
		}
		if baseAttr.Type == nil {
			// DSL did not contain an "Attribute" declaration
			baseAttr.Type = design.String
		}
		parent.Type.(design.Object)[name] = baseAttr
	}
}
Exemple #2
0
// Payload implements the action payload DSL. An action payload describes the HTTP request body
// data structure. The function accepts either a type or a DSL that describes the payload members
// using the Member DSL which accepts the same syntax as the Attribute DSL. This function can be
// called passing in a type, a DSL or both. Examples:
//
//	Payload(BottlePayload)		// Request payload is described by the BottlePayload type
//
//	Payload(func() {		// Request payload is an object and is described inline
//		Member("Name")
//	})
//
//	Payload(BottlePayload, func() {	// Request payload is described by merging the inline
//		Required("Name")	// definition into the BottlePayload type.
//	})
//
func Payload(p interface{}, dsls ...func()) {
	if len(dsls) > 1 {
		ReportError("too many arguments given to Payload")
		return
	}
	if a, ok := actionDefinition(true); ok {
		var att *design.AttributeDefinition
		var dsl func()
		switch actual := p.(type) {
		case func():
			dsl = actual
			att = newAttribute(a.Parent.MediaType)
			att.Type = design.Object{}
		case *design.AttributeDefinition:
			att = actual.Dup()
		case design.DataStructure:
			att = actual.Definition().Dup()
		case string:
			ut, ok := design.Design.Types[actual]
			if !ok {
				ReportError("unknown payload type %s", actual)
			}
			att = ut.AttributeDefinition.Dup()
		case *design.Array:
			att = &design.AttributeDefinition{Type: actual}
		case *design.Hash:
			att = &design.AttributeDefinition{Type: actual}
		case design.Primitive:
			att = &design.AttributeDefinition{Type: actual}
		}
		if len(dsls) == 1 {
			if dsl != nil {
				ReportError("invalid arguments in Payload call, must be (type), (dsl) or (type, dsl)")
			}
			dsl = dsls[0]
		}
		if dsl != nil {
			ExecuteDSL(dsl, att)
		}
		rn := inflect.Camelize(a.Parent.Name)
		an := inflect.Camelize(a.Name)
		a.Payload = &design.UserTypeDefinition{
			AttributeDefinition: att,
			TypeName:            fmt.Sprintf("%s%sPayload", an, rn),
		}
	}
}
Exemple #3
0
	BeforeEach(func() {
		codegen.TempCount = 0
	})

	Describe("ValidationChecker", func() {
		Context("given an attribute definition and validations", func() {
			var attType design.DataType
			var validations []design.ValidationDefinition

			att := new(design.AttributeDefinition)
			target := "val"
			context := "context"
			var code string // generated code

			JustBeforeEach(func() {
				att.Type = attType
				att.Validations = validations
				code = codegen.ValidationChecker(att, false, false, target, context, 1)
			})

			Context("of enum", func() {
				BeforeEach(func() {
					attType = design.Integer
					enumVal := &design.EnumValidationDefinition{
						Values: []interface{}{1, 2, 3},
					}
					validations = []design.ValidationDefinition{enumVal}
				})

				It("produces the validation go code", func() {
					Ω(code).Should(Equal(enumValCode))
Exemple #4
0
package dsl

import (
	"regexp"
	"strconv"
	"strings"

	"github.com/raphael/goa/design"
)

// Attribute implements the attribute definition DSL. An attribute describes a data structure
// recursively. Attributes are used for describing request headers, parameters and payloads -
// response bodies and headers - media types and types. An attribute definition is recursive:
// attributes may include other attributes. At the basic level an attribute has a name,
// a type and optionally a default value and validation rules. The type of an attribute can be one of:
//
// * The primitive types Boolean, Integer, Number or String.
//
// * A type defined via the Type function.
//
// * A media type defined via the MediaType function.
//
// * An object described recursively with child attributes.
//
// * An array defined using the ArrayOf function.
//
// * An hashmap defined using the HashOf function.
//
// Attributes can be defined using the Attribute, Param, Member or Header functions depending
// on where the definition appears. The syntax for all these DSL is the same.
// Here are some examples:
//
//	 Attribute("name")             //  Defines an attribute of type String
//
//	 Attribute("name", func() {
//	 	Pattern("^foo")        // Adds a validation rule to the attribute
//	 })
//
//	 Attribute("name", Integer)    // Defines an attribute of type Integer
//
//	 Attribute("name", Integer, func() {
//	 	Default(42)            // With a default value
//	 })
//
//	 Attribute("name", Integer, "description") // Specifies a description
//
//	 Attribute("name", Integer, "description", func() {
//	 	Enum(1, 2)             // And validation rules
//	 })
//
// Nested attributes:
//
//	 Attribute("nested", func() {
//	 	Description("description")
//	 	Attribute("child")
//	 	Attribute("child2", func() {
//	 		// ....
//	 	})
//              Required("child")
//	 })
//
// Here are all the valid usage of the Attribute function:
//
//	 Attribute(name string, dataType DataType, description string, dsl func())
//
//	 Attribute(name string, dataType DataType, description string)
//
//	 Attribute(name string, dataType DataType, dsl func())
//
//	 Attribute(name string, dataType DataType)
//
//	 Attribute(name string, dsl func()) /* dataType is String or Object (if DSL defines child attributes) */
//
//	 Attribute(name string) /* dataType is String */
func Attribute(name string, args ...interface{}) {
	var parent *design.AttributeDefinition
	if at, ok := attributeDefinition(false); ok {
		parent = at
	} else if mt, ok := mediaTypeDefinition(true); ok {
		parent = mt.AttributeDefinition
	}
	if parent != nil {
		if parent.Type == nil {
			parent.Type = design.Object{}
		} else if _, ok := parent.Type.(design.Object); !ok {
			ReportError("can't define child attributes on attribute of type %s", parent.Type.Name())
			return
		}
		var baseAttr *design.AttributeDefinition
		if parent.Reference != nil {
			for n, att := range parent.Reference.ToObject() {
				if n == name {
					baseAttr = att.Dup()
					break
				}
			}
		}
		var dataType design.DataType
		var description string
		var dsl func()
		var ok bool
		if len(args) == 0 {
			if baseAttr != nil {
				dataType = baseAttr.Type
			} else {
				dataType = design.String
			}
		} else if len(args) == 1 {
			if dsl, ok = args[0].(func()); !ok {
				if dataType, ok = args[0].(design.DataType); !ok {
					invalidArgError("DataType or func()", args[0])
				}
			} else if baseAttr != nil {
				dataType = baseAttr.Type
			}
		} else if len(args) == 2 {
			if dataType, ok = args[0].(design.DataType); !ok {
				invalidArgError("DataType", args[0])
			}
			if dsl, ok = args[1].(func()); !ok {
				if description, ok = args[1].(string); !ok {
					invalidArgError("string or func()", args[1])
				}
			}
		} else if len(args) == 3 {
			if dataType, ok = args[0].(design.DataType); !ok {
				invalidArgError("DataType", args[0])
			}
			if description, ok = args[1].(string); !ok {
				invalidArgError("string", args[1])
			}
			if dsl, ok = args[2].(func()); !ok {
				invalidArgError("func()", args[2])
			}
		} else {
			ReportError("too many arguments in call to Attribute")
		}
		var att *design.AttributeDefinition
		if baseAttr != nil {
			att = baseAttr
			if description != "" {
				att.Description = description
			}
			if dataType != nil {
				att.Type = dataType
			}
		} else {
			att = &design.AttributeDefinition{
				Type:        dataType,
				Description: description,
			}
		}
		att.Reference = parent.Reference
		if dsl != nil {
			executeDSL(dsl, att)
		}
		if att.Type == nil {
			// DSL did not contain an "Attribute" declaration
			att.Type = design.String
		}
		parent.Type.(design.Object)[name] = att
	}
}