forked from goadesign/goa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
resource.go
122 lines (116 loc) · 5.16 KB
/
resource.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package apidsl
import (
"github.com/goadesign/goa/design"
"github.com/goadesign/goa/dslengine"
)
// Resource implements the resource definition dsl. There is one resource definition per resource
// exposed by the API. The resource dsl allows setting the resource default media type. This media
// type is used to render the response body of actions that return the OK response (unless the
// action overrides the default). The default media type also sets the properties of the request
// payload attributes with the same name. See DefaultMedia.
//
// The resource dsl also allows listing the supported resource collection and resource collection
// item actions. Each action corresponds to a specific API endpoint. See Action.
//
// The resource dsl can also specify a parent resource. Parent resources have two effects.
// First, they set the prefix of all resource action paths to the parent resource href. Note that
// actions can override the path using an absolute path (that is a path starting with "//").
// Second, goa uses the parent resource href coupled with the resource BasePath if any to build
// hrefs to the resource collection or resource collection items. By default goa uses the show
// action if present to compute a resource href (basically concatenating the parent resource href
// with the base path and show action path). The resource definition may specify a canonical action
// via CanonicalActionName to override that default. Here is an example of a resource definition:
//
// Resource("bottle", func() {
// Description("A wine bottle") // Resource description
// DefaultMedia(BottleMedia) // Resource default media type
// BasePath("/bottles") // Common resource action path prefix if not ""
// Parent("account") // Name of parent resource if any
// CanonicalActionName("get") // Name of action that returns canonical representation if not "show"
// UseTrait("Authenticated") // Included trait if any, can appear more than once
//
// 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 prefligh request response
// Credentials() // Sets Access-Control-Allow-Credentials header
// })
//
// Response(Unauthorized, ErrorMedia) // Common responses to all actions
// Response(BadRequest, ErrorMedia)
//
// Action("show", func() { // Action definition, can appear more than once
// // ... Action dsl
// })
// })
func Resource(name string, dsl func()) *design.ResourceDefinition {
if design.Design.Resources == nil {
design.Design.Resources = make(map[string]*design.ResourceDefinition)
}
if !dslengine.IsTopLevelDefinition() {
dslengine.IncompatibleDSL()
return nil
}
if _, ok := design.Design.Resources[name]; ok {
dslengine.ReportError("resource %#v is defined twice", name)
return nil
}
resource := design.NewResourceDefinition(name, dsl)
design.Design.Resources[name] = resource
return resource
}
// DefaultMedia sets a resource default media type by identifier or by reference using a value
// returned by MediaType:
//
// var _ = Resource("bottle", func() {
// DefaultMedia(BottleMedia)
// // ...
// })
//
// var _ = Resource("region", func() {
// DefaultMedia("vnd.goa.region")
// // ...
// })
//
// The default media type is used to build OK response definitions when no specific media type is
// given in the Response function call. The default media type is also used to set the default
// properties of attributes listed in action payloads and params. So if a media type defines an
// attribute "name" with associated validations then simply calling Attribute("name") inside a
// request Payload or Param defines the attribute with the same type and validations.
func DefaultMedia(val interface{}, viewName ...string) {
if r, ok := resourceDefinition(); ok {
if m, ok := val.(*design.MediaTypeDefinition); ok {
if m.UserTypeDefinition == nil {
dslengine.ReportError("invalid media type specification, media type is not initialized")
} else {
r.MediaType = m.Identifier
m.Resource = r
}
} else if identifier, ok := val.(string); ok {
r.MediaType = identifier
} else {
dslengine.ReportError("media type must be a string or a *design.MediaTypeDefinition, got %#v", val)
return
}
if len(viewName) == 1 {
r.DefaultViewName = viewName[0]
} else if len(viewName) > 1 {
dslengine.ReportError("too many arguments given to DefaultMedia")
}
}
}
// Parent sets the resource parent. The parent resource is used to compute the path to the resource
// actions as well as resource collection item hrefs. See Resource.
func Parent(p string) {
if r, ok := resourceDefinition(); ok {
r.ParentName = p
}
}
// CanonicalActionName sets the name of the action used to compute the resource collection and
// resource collection items hrefs. See Resource.
func CanonicalActionName(a string) {
if r, ok := resourceDefinition(); ok {
r.CanonicalActionName = a
}
}