github.com/josephbuchma/goa@v1.2.0/design/apidsl/type.go (about) 1 package apidsl 2 3 import ( 4 "github.com/goadesign/goa/design" 5 "github.com/goadesign/goa/dslengine" 6 ) 7 8 // Type implements the type definition dsl. A type definition describes a data structure consisting 9 // of attributes. Each attribute has a type which can also refer to a type definition (or use a 10 // primitive type or nested attibutes). The dsl syntax for define a type definition is the 11 // Attribute dsl, see Attribute. 12 // 13 // On top of specifying any attribute type, type definitions can also be used to describe the data 14 // structure of a request payload. They can also be used by media type definitions as reference, see 15 // Reference. Here is an example: 16 // 17 // Type("createPayload", func() { 18 // Description("Type of create and upload action payloads") 19 // Attribute("name", String, "name of bottle") 20 // Attribute("origin", Origin, "Details on wine origin") // See Origin definition below 21 // Required("name") 22 // }) 23 // 24 // var Origin = Type("origin", func() { 25 // Description("Origin of bottle") 26 // Attribute("Country") 27 // }) 28 // 29 // This function returns the newly defined type so the value can be used throughout the dsl. 30 func Type(name string, dsl func()) *design.UserTypeDefinition { 31 if design.Design.Types == nil { 32 design.Design.Types = make(map[string]*design.UserTypeDefinition) 33 } else if _, ok := design.Design.Types[name]; ok { 34 dslengine.ReportError("type %#v defined twice", name) 35 return nil 36 } 37 38 if !dslengine.IsTopLevelDefinition() { 39 dslengine.IncompatibleDSL() 40 return nil 41 } 42 43 t := &design.UserTypeDefinition{ 44 TypeName: name, 45 AttributeDefinition: &design.AttributeDefinition{DSLFunc: dsl}, 46 } 47 if dsl == nil { 48 t.Type = design.String 49 } else { 50 t.Type = make(design.Object) 51 } 52 design.Design.Types[name] = t 53 return t 54 } 55 56 // ArrayOf creates an array type from its element type. The result can be used anywhere a type can. 57 // Examples: 58 // 59 // var Bottle = Type("bottle", func() { 60 // Attribute("name") 61 // }) 62 // 63 // var Bottles = ArrayOf(Bottle) 64 // 65 // Action("update", func() { 66 // Params(func() { 67 // Param("ids", ArrayOf(Integer)) 68 // }) 69 // Payload(ArrayOf(Bottle)) // Equivalent to Payload(Bottles) 70 // }) 71 // 72 // ArrayOf accepts an optional DSL as second argument which allows providing validations for the 73 // elements of the array: 74 // 75 // var Names = ArrayOf(String, func() { 76 // Pattern("[a-zA-Z]+") 77 // }) 78 // 79 // If you are looking to return a collection of elements in a Response clause, refer to 80 // CollectionOf. ArrayOf creates a type, where CollectionOf creates a media type. 81 func ArrayOf(v interface{}, dsl ...func()) *design.Array { 82 var t design.DataType 83 var ok bool 84 t, ok = v.(design.DataType) 85 if !ok { 86 if name, ok := v.(string); ok { 87 if ut, ok := design.Design.Types[name]; ok { 88 t = ut 89 } else if mt, ok := design.Design.MediaTypes[name]; ok { 90 t = mt 91 } 92 } 93 } 94 // never return nil to avoid panics, errors are reported after DSL execution 95 res := &design.Array{ElemType: &design.AttributeDefinition{Type: design.String}} 96 if t == nil { 97 dslengine.ReportError("invalid ArrayOf argument: not a type and not a known user type name") 98 return res 99 } 100 if len(dsl) > 1 { 101 dslengine.ReportError("ArrayOf: too many arguments") 102 return res 103 } 104 at := design.AttributeDefinition{Type: t} 105 if len(dsl) == 1 { 106 dslengine.Execute(dsl[0], &at) 107 } 108 return &design.Array{ElemType: &at} 109 } 110 111 // HashOf creates a hash map from its key and element types. The result can be used anywhere a type 112 // can. Examples: 113 // 114 // var Bottle = Type("bottle", func() { 115 // Attribute("name") 116 // }) 117 // 118 // var RatedBottles = HashOf(String, Bottle) 119 // 120 // Action("updateRatings", func() { 121 // Payload(func() { 122 // Member("ratings", HashOf(String, Integer)) // Artificial examples... 123 // Member("bottles", RatedBottles) 124 // }) 125 // 126 // HashOf accepts optional DSLs as third and fourth argument which allows providing validations for 127 // the keys and values of the hash respectively: 128 // 129 // var RatedBottles = HashOf(String, Bottle, func() { 130 // Pattern("[a-zA-Z]+") // Validate bottle names 131 // }) 132 // 133 // func ValidateKey() { 134 // Pattern("^foo") 135 // } 136 // 137 // func TypeValue() { 138 // Metadata("struct:field:type", "json.RawMessage", "encoding/json") 139 // } 140 // 141 // var Mappings = HashOf(String, String, ValidateKey, TypeValue) 142 // 143 func HashOf(k, v design.DataType, dsls ...func()) *design.Hash { 144 kat := design.AttributeDefinition{Type: k} 145 vat := design.AttributeDefinition{Type: v} 146 if len(dsls) > 2 { 147 // never return nil to avoid panics, errors are reported after DSL execution 148 dslengine.ReportError("HashOf: too many arguments") 149 return &design.Hash{KeyType: &kat, ElemType: &vat} 150 } 151 if len(dsls) >= 1 { 152 dslengine.Execute(dsls[0], &kat) 153 if len(dsls) == 2 { 154 dslengine.Execute(dsls[1], &vat) 155 } 156 } 157 return &design.Hash{KeyType: &kat, ElemType: &vat} 158 }