github.com/ManabuSeki/goa-v1@v1.4.3/design/api.go (about) 1 package design 2 3 import ( 4 "mime" 5 "regexp" 6 "sort" 7 "strings" 8 9 "github.com/goadesign/goa/dslengine" 10 ) 11 12 // MediaTypeRoot is the data structure that represents the additional DSL definition root 13 // that contains the media type definition set created by CollectionOf index by canonical id. 14 type MediaTypeRoot map[string]*MediaTypeDefinition 15 16 // List of all built-in response names. 17 const ( 18 Continue = "Continue" 19 SwitchingProtocols = "SwitchingProtocols" 20 21 OK = "OK" 22 Created = "Created" 23 Accepted = "Accepted" 24 NonAuthoritativeInfo = "NonAuthoritativeInfo" 25 NoContent = "NoContent" 26 ResetContent = "ResetContent" 27 PartialContent = "PartialContent" 28 29 MultipleChoices = "MultipleChoices" 30 MovedPermanently = "MovedPermanently" 31 Found = "Found" 32 SeeOther = "SeeOther" 33 NotModified = "NotModified" 34 UseProxy = "UseProxy" 35 TemporaryRedirect = "TemporaryRedirect" 36 37 BadRequest = "BadRequest" 38 Unauthorized = "Unauthorized" 39 PaymentRequired = "PaymentRequired" 40 Forbidden = "Forbidden" 41 NotFound = "NotFound" 42 MethodNotAllowed = "MethodNotAllowed" 43 NotAcceptable = "NotAcceptable" 44 ProxyAuthRequired = "ProxyAuthRequired" 45 RequestTimeout = "RequestTimeout" 46 Conflict = "Conflict" 47 Gone = "Gone" 48 LengthRequired = "LengthRequired" 49 PreconditionFailed = "PreconditionFailed" 50 RequestEntityTooLarge = "RequestEntityTooLarge" 51 RequestURITooLong = "RequestURITooLong" 52 UnsupportedMediaType = "UnsupportedMediaType" 53 RequestedRangeNotSatisfiable = "RequestedRangeNotSatisfiable" 54 ExpectationFailed = "ExpectationFailed" 55 Teapot = "Teapot" 56 UnprocessableEntity = "UnprocessableEntity" 57 58 InternalServerError = "InternalServerError" 59 NotImplemented = "NotImplemented" 60 BadGateway = "BadGateway" 61 ServiceUnavailable = "ServiceUnavailable" 62 GatewayTimeout = "GatewayTimeout" 63 HTTPVersionNotSupported = "HTTPVersionNotSupported" 64 ) 65 66 var ( 67 // Design being built by DSL. 68 Design *APIDefinition 69 70 // GeneratedMediaTypes contains DSL definitions that were created by the design DSL and 71 // need to be executed as a second pass. 72 // An example of this are media types defined with CollectionOf: the element media type 73 // must be defined first then the definition created by CollectionOf must execute. 74 GeneratedMediaTypes MediaTypeRoot 75 76 // ProjectedMediaTypes is a cache used by the MediaType strut Project method. 77 ProjectedMediaTypes MediaTypeRoot 78 79 // WildcardRegex is the regular expression used to capture path parameters. 80 WildcardRegex = regexp.MustCompile(`/(?::|\*)([a-zA-Z0-9_]+)`) 81 82 // DefaultDecoders contains the decoding definitions used when no Consumes DSL is found. 83 DefaultDecoders []*EncodingDefinition 84 85 // DefaultEncoders contains the encoding definitions used when no Produces DSL is found. 86 DefaultEncoders []*EncodingDefinition 87 88 // KnownEncoders contains the list of encoding packages and factories known by goa indexed 89 // by MIME type. 90 KnownEncoders = map[string]string{ 91 "application/json": "github.com/goadesign/goa", 92 "application/xml": "github.com/goadesign/goa", 93 "application/gob": "github.com/goadesign/goa", 94 "application/x-gob": "github.com/goadesign/goa", 95 "application/binc": "github.com/goadesign/goa/encoding/binc", 96 "application/x-binc": "github.com/goadesign/goa/encoding/binc", 97 "application/cbor": "github.com/goadesign/goa/encoding/cbor", 98 "application/x-cbor": "github.com/goadesign/goa/encoding/cbor", 99 "application/msgpack": "github.com/goadesign/goa/encoding/msgpack", 100 "application/x-msgpack": "github.com/goadesign/goa/encoding/msgpack", 101 } 102 103 // KnownEncoderFunctions contains the list of encoding encoder and decoder functions known 104 // by goa indexed by MIME type. 105 KnownEncoderFunctions = map[string][2]string{ 106 "application/json": {"NewJSONEncoder", "NewJSONDecoder"}, 107 "application/xml": {"NewXMLEncoder", "NewXMLDecoder"}, 108 "application/gob": {"NewGobEncoder", "NewGobDecoder"}, 109 "application/x-gob": {"NewGobEncoder", "NewGobDecoder"}, 110 "application/binc": {"NewEncoder", "NewDecoder"}, 111 "application/x-binc": {"NewEncoder", "NewDecoder"}, 112 "application/cbor": {"NewEncoder", "NewDecoder"}, 113 "application/x-cbor": {"NewEncoder", "NewDecoder"}, 114 "application/msgpack": {"NewEncoder", "NewDecoder"}, 115 "application/x-msgpack": {"NewEncoder", "NewDecoder"}, 116 } 117 118 // JSONContentTypes list the Content-Type header values that cause goa to encode or decode 119 // JSON by default. 120 JSONContentTypes = []string{"application/json"} 121 122 // XMLContentTypes list the Content-Type header values that cause goa to encode or decode 123 // XML by default. 124 XMLContentTypes = []string{"application/xml"} 125 126 // GobContentTypes list the Content-Type header values that cause goa to encode or decode 127 // Gob by default. 128 GobContentTypes = []string{"application/gob", "application/x-gob"} 129 130 // ErrorMediaIdentifier is the media type identifier used for error responses. 131 ErrorMediaIdentifier = "application/vnd.goa.error" 132 133 // ErrorMedia is the built-in media type for error responses. 134 ErrorMedia = &MediaTypeDefinition{ 135 UserTypeDefinition: &UserTypeDefinition{ 136 AttributeDefinition: &AttributeDefinition{ 137 Type: errorMediaType, 138 Description: "Error response media type", 139 Example: map[string]interface{}{ 140 "id": "3F1FKVRR", 141 "status": "400", 142 "code": "invalid_value", 143 "detail": "Value of ID must be an integer", 144 "meta": map[string]interface{}{"timestamp": 1458609066}, 145 }, 146 }, 147 TypeName: "error", 148 }, 149 Identifier: ErrorMediaIdentifier, 150 Views: map[string]*ViewDefinition{"default": errorMediaView}, 151 } 152 153 errorMediaType = Object{ 154 "id": &AttributeDefinition{ 155 Type: String, 156 Description: "a unique identifier for this particular occurrence of the problem.", 157 Example: "3F1FKVRR", 158 }, 159 "status": &AttributeDefinition{ 160 Type: String, 161 Description: "the HTTP status code applicable to this problem, expressed as a string value.", 162 Example: "400", 163 }, 164 "code": &AttributeDefinition{ 165 Type: String, 166 Description: "an application-specific error code, expressed as a string value.", 167 Example: "invalid_value", 168 }, 169 "detail": &AttributeDefinition{ 170 Type: String, 171 Description: "a human-readable explanation specific to this occurrence of the problem.", 172 Example: "Value of ID must be an integer", 173 }, 174 "meta": &AttributeDefinition{ 175 Type: &Hash{ 176 KeyType: &AttributeDefinition{Type: String}, 177 ElemType: &AttributeDefinition{Type: Any}, 178 }, 179 Description: "a meta object containing non-standard meta-information about the error.", 180 Example: map[string]interface{}{"timestamp": 1458609066}, 181 }, 182 } 183 184 errorMediaView = &ViewDefinition{ 185 AttributeDefinition: &AttributeDefinition{Type: errorMediaType}, 186 Name: "default", 187 } 188 ) 189 190 func init() { 191 goa := "github.com/goadesign/goa" 192 DefaultEncoders = []*EncodingDefinition{ 193 {MIMETypes: JSONContentTypes, PackagePath: goa, Function: "NewJSONEncoder"}, 194 {MIMETypes: XMLContentTypes, PackagePath: goa, Function: "NewXMLEncoder"}, 195 {MIMETypes: GobContentTypes, PackagePath: goa, Function: "NewGobEncoder"}, 196 } 197 DefaultDecoders = []*EncodingDefinition{ 198 {MIMETypes: JSONContentTypes, PackagePath: goa, Function: "NewJSONDecoder"}, 199 {MIMETypes: XMLContentTypes, PackagePath: goa, Function: "NewXMLDecoder"}, 200 {MIMETypes: GobContentTypes, PackagePath: goa, Function: "NewGobDecoder"}, 201 } 202 errorMediaView.Parent = ErrorMedia 203 } 204 205 // CanonicalIdentifier returns the media type identifier sans suffix 206 // which is what the DSL uses to store and lookup media types. 207 func CanonicalIdentifier(identifier string) string { 208 base, params, err := mime.ParseMediaType(identifier) 209 if err != nil { 210 return identifier 211 } 212 id := base 213 if i := strings.Index(id, "+"); i != -1 { 214 id = id[:i] 215 } 216 return mime.FormatMediaType(id, params) 217 } 218 219 // HasKnownEncoder returns true if the encoder for the given MIME type is known by goa. 220 // MIME types with unknown encoders must be associated with a package path explicitly in the DSL. 221 func HasKnownEncoder(mimeType string) bool { 222 return KnownEncoders[mimeType] != "" 223 } 224 225 // ExtractWildcards returns the names of the wildcards that appear in path. 226 func ExtractWildcards(path string) []string { 227 matches := WildcardRegex.FindAllStringSubmatch(path, -1) 228 wcs := make([]string, len(matches)) 229 for i, m := range matches { 230 wcs[i] = m[1] 231 } 232 return wcs 233 } 234 235 // DSLName is displayed to the user when the DSL executes. 236 func (r MediaTypeRoot) DSLName() string { 237 return "Generated Media Types" 238 } 239 240 // DependsOn return the DSL roots the generated media types DSL root depends on, that's the API DSL. 241 func (r MediaTypeRoot) DependsOn() []dslengine.Root { 242 return []dslengine.Root{Design} 243 } 244 245 // IterateSets iterates over the one generated media type definition set. 246 func (r MediaTypeRoot) IterateSets(iterator dslengine.SetIterator) { 247 canonicalIDs := make([]string, len(r)) 248 i := 0 249 for _, mt := range r { 250 canonicalID := CanonicalIdentifier(mt.Identifier) 251 Design.MediaTypes[canonicalID] = mt 252 canonicalIDs[i] = canonicalID 253 i++ 254 } 255 sort.Strings(canonicalIDs) 256 set := make([]dslengine.Definition, len(canonicalIDs)) 257 for i, cid := range canonicalIDs { 258 set[i] = Design.MediaTypes[cid] 259 } 260 iterator(set) 261 } 262 263 // Reset deletes all the keys. 264 func (r MediaTypeRoot) Reset() { 265 for k := range r { 266 delete(r, k) 267 } 268 }