Skip to content

Commit 12647e7

Browse files
committed
Introduce controllers
as a first class abstraction. The Controller interfacr makes it possible to define middleware and error handlers that apply to a single controller rather than the entire service.
1 parent d23c391 commit 12647e7

19 files changed

+186
-97
lines changed

context_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ var _ = Describe("Context", func() {
112112
})
113113

114114
JustBeforeEach(func() {
115-
httpHandle = goa.NewHTTPRouterHandle(app, resName, actName, handler)
115+
ctrl := app.NewController(resName)
116+
httpHandle = ctrl.NewHTTPRouterHandle(actName, handler)
116117
httpHandle(rw, request, params)
117118
})
118119

cors/middleware.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ func MountPreflightController(service goa.Service, spec Specification) {
128128
h := func(ctx *goa.Context) error {
129129
return ctx.Respond(200, nil)
130130
}
131-
router.OPTIONS(path, goa.NewHTTPRouterHandle(service, "CORS", "preflight", h))
131+
ctrl := service.NewController("cors")
132+
router.OPTIONS(path, ctrl.NewHTTPRouterHandle("preflight", h))
132133
}
133134
}
134135
}

cors/middleware_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ var _ = Describe("Middleware", func() {
3333
service.Use(cors.Middleware(spec))
3434
router := service.HTTPHandler().(*httprouter.Router)
3535
h := func(ctx *goa.Context) error { return ctx.Respond(200, nil) }
36-
router.Handle(method, path, goa.NewHTTPRouterHandle(service, "", "", h))
37-
router.Handle("OPTIONS", path, goa.NewHTTPRouterHandle(service, "", "", optionsHandler))
36+
ctrl := service.NewController("test")
37+
router.Handle(method, path, ctrl.NewHTTPRouterHandle("", h))
38+
router.Handle("OPTIONS", path, ctrl.NewHTTPRouterHandle("", optionsHandler))
3839
cors.MountPreflightController(service, spec)
3940
portIndex++
4041
port := 54511 + portIndex

examples/cellar/app/contexts.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// Generated with goagen v0.0.1, command line:
55
// $ goagen
6-
// --out=.
6+
// --out=$(GOPATH)/src/github.com/raphael/goa/examples/cellar
77
// --design=github.com/raphael/goa/examples/cellar/design
88
// --pkg=app
99
//

examples/cellar/app/controllers.go

+13-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// Generated with goagen v0.0.1, command line:
55
// $ goagen
6-
// --out=.
6+
// --out=$(GOPATH)/src/github.com/raphael/goa/examples/cellar
77
// --design=github.com/raphael/goa/examples/cellar/design
88
// --pkg=app
99
//
@@ -19,6 +19,7 @@ import (
1919

2020
// AccountController is the controller interface for the Account actions.
2121
type AccountController interface {
22+
goa.Controller
2223
Create(*CreateAccountContext) error
2324
Delete(*DeleteAccountContext) error
2425
Show(*ShowAccountContext) error
@@ -36,7 +37,7 @@ func MountAccountController(service goa.Service, ctrl AccountController) {
3637
}
3738
return ctrl.Create(ctx)
3839
}
39-
router.Handle("POST", "/cellar/accounts", goa.NewHTTPRouterHandle(service, "Account", "Create", h))
40+
router.Handle("POST", "/cellar/accounts", ctrl.NewHTTPRouterHandle("Create", h))
4041
service.Info("mount", "ctrl", "Account", "action", "Create", "route", "POST /cellar/accounts")
4142
h = func(c *goa.Context) error {
4243
ctx, err := NewDeleteAccountContext(c)
@@ -45,7 +46,7 @@ func MountAccountController(service goa.Service, ctrl AccountController) {
4546
}
4647
return ctrl.Delete(ctx)
4748
}
48-
router.Handle("DELETE", "/cellar/accounts/:accountID", goa.NewHTTPRouterHandle(service, "Account", "Delete", h))
49+
router.Handle("DELETE", "/cellar/accounts/:accountID", ctrl.NewHTTPRouterHandle("Delete", h))
4950
service.Info("mount", "ctrl", "Account", "action", "Delete", "route", "DELETE /cellar/accounts/:accountID")
5051
h = func(c *goa.Context) error {
5152
ctx, err := NewShowAccountContext(c)
@@ -54,7 +55,7 @@ func MountAccountController(service goa.Service, ctrl AccountController) {
5455
}
5556
return ctrl.Show(ctx)
5657
}
57-
router.Handle("GET", "/cellar/accounts/:accountID", goa.NewHTTPRouterHandle(service, "Account", "Show", h))
58+
router.Handle("GET", "/cellar/accounts/:accountID", ctrl.NewHTTPRouterHandle("Show", h))
5859
service.Info("mount", "ctrl", "Account", "action", "Show", "route", "GET /cellar/accounts/:accountID")
5960
h = func(c *goa.Context) error {
6061
ctx, err := NewUpdateAccountContext(c)
@@ -63,12 +64,13 @@ func MountAccountController(service goa.Service, ctrl AccountController) {
6364
}
6465
return ctrl.Update(ctx)
6566
}
66-
router.Handle("PUT", "/cellar/accounts/:accountID", goa.NewHTTPRouterHandle(service, "Account", "Update", h))
67+
router.Handle("PUT", "/cellar/accounts/:accountID", ctrl.NewHTTPRouterHandle("Update", h))
6768
service.Info("mount", "ctrl", "Account", "action", "Update", "route", "PUT /cellar/accounts/:accountID")
6869
}
6970

7071
// BottleController is the controller interface for the Bottle actions.
7172
type BottleController interface {
73+
goa.Controller
7274
Create(*CreateBottleContext) error
7375
Delete(*DeleteBottleContext) error
7476
List(*ListBottleContext) error
@@ -88,7 +90,7 @@ func MountBottleController(service goa.Service, ctrl BottleController) {
8890
}
8991
return ctrl.Create(ctx)
9092
}
91-
router.Handle("POST", "/cellar/accounts/:accountID/bottles", goa.NewHTTPRouterHandle(service, "Bottle", "Create", h))
93+
router.Handle("POST", "/cellar/accounts/:accountID/bottles", ctrl.NewHTTPRouterHandle("Create", h))
9294
service.Info("mount", "ctrl", "Bottle", "action", "Create", "route", "POST /cellar/accounts/:accountID/bottles")
9395
h = func(c *goa.Context) error {
9496
ctx, err := NewDeleteBottleContext(c)
@@ -97,7 +99,7 @@ func MountBottleController(service goa.Service, ctrl BottleController) {
9799
}
98100
return ctrl.Delete(ctx)
99101
}
100-
router.Handle("DELETE", "/cellar/accounts/:accountID/bottles/:bottleID", goa.NewHTTPRouterHandle(service, "Bottle", "Delete", h))
102+
router.Handle("DELETE", "/cellar/accounts/:accountID/bottles/:bottleID", ctrl.NewHTTPRouterHandle("Delete", h))
101103
service.Info("mount", "ctrl", "Bottle", "action", "Delete", "route", "DELETE /cellar/accounts/:accountID/bottles/:bottleID")
102104
h = func(c *goa.Context) error {
103105
ctx, err := NewListBottleContext(c)
@@ -106,7 +108,7 @@ func MountBottleController(service goa.Service, ctrl BottleController) {
106108
}
107109
return ctrl.List(ctx)
108110
}
109-
router.Handle("GET", "/cellar/accounts/:accountID/bottles", goa.NewHTTPRouterHandle(service, "Bottle", "List", h))
111+
router.Handle("GET", "/cellar/accounts/:accountID/bottles", ctrl.NewHTTPRouterHandle("List", h))
110112
service.Info("mount", "ctrl", "Bottle", "action", "List", "route", "GET /cellar/accounts/:accountID/bottles")
111113
h = func(c *goa.Context) error {
112114
ctx, err := NewRateBottleContext(c)
@@ -115,7 +117,7 @@ func MountBottleController(service goa.Service, ctrl BottleController) {
115117
}
116118
return ctrl.Rate(ctx)
117119
}
118-
router.Handle("PUT", "/cellar/accounts/:accountID/bottles/:bottleID/actions/rate", goa.NewHTTPRouterHandle(service, "Bottle", "Rate", h))
120+
router.Handle("PUT", "/cellar/accounts/:accountID/bottles/:bottleID/actions/rate", ctrl.NewHTTPRouterHandle("Rate", h))
119121
service.Info("mount", "ctrl", "Bottle", "action", "Rate", "route", "PUT /cellar/accounts/:accountID/bottles/:bottleID/actions/rate")
120122
h = func(c *goa.Context) error {
121123
ctx, err := NewShowBottleContext(c)
@@ -124,7 +126,7 @@ func MountBottleController(service goa.Service, ctrl BottleController) {
124126
}
125127
return ctrl.Show(ctx)
126128
}
127-
router.Handle("GET", "/cellar/accounts/:accountID/bottles/:bottleID", goa.NewHTTPRouterHandle(service, "Bottle", "Show", h))
129+
router.Handle("GET", "/cellar/accounts/:accountID/bottles/:bottleID", ctrl.NewHTTPRouterHandle("Show", h))
128130
service.Info("mount", "ctrl", "Bottle", "action", "Show", "route", "GET /cellar/accounts/:accountID/bottles/:bottleID")
129131
h = func(c *goa.Context) error {
130132
ctx, err := NewUpdateBottleContext(c)
@@ -133,6 +135,6 @@ func MountBottleController(service goa.Service, ctrl BottleController) {
133135
}
134136
return ctrl.Update(ctx)
135137
}
136-
router.Handle("PATCH", "/cellar/accounts/:accountID/bottles/:bottleID", goa.NewHTTPRouterHandle(service, "Bottle", "Update", h))
138+
router.Handle("PATCH", "/cellar/accounts/:accountID/bottles/:bottleID", ctrl.NewHTTPRouterHandle("Update", h))
137139
service.Info("mount", "ctrl", "Bottle", "action", "Update", "route", "PATCH /cellar/accounts/:accountID/bottles/:bottleID")
138140
}

examples/cellar/app/hrefs.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// Generated with goagen v0.0.1, command line:
55
// $ goagen
6-
// --out=.
6+
// --out=$(GOPATH)/src/github.com/raphael/goa/examples/cellar
77
// --design=github.com/raphael/goa/examples/cellar/design
88
// --pkg=app
99
//

examples/cellar/app/media_types.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// Generated with goagen v0.0.1, command line:
55
// $ goagen
6-
// --out=.
6+
// --out=$(GOPATH)/src/github.com/raphael/goa/examples/cellar
77
// --design=github.com/raphael/goa/examples/cellar/design
88
// --pkg=app
99
//

examples/cellar/app/user_types.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// Generated with goagen v0.0.1, command line:
55
// $ goagen
6-
// --out=.
6+
// --out=$(GOPATH)/src/github.com/raphael/goa/examples/cellar
77
// --design=github.com/raphael/goa/examples/cellar/design
88
// --pkg=app
99
//

examples/cellar/controllers/account.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
package controllers
22

3-
import "github.com/raphael/goa/examples/cellar/app"
3+
import (
4+
"github.com/raphael/goa"
5+
"github.com/raphael/goa/examples/cellar/app"
6+
)
47

58
// AccountController implements the account resource.
69
type AccountController struct {
10+
goa.Controller
711
db *DB
812
}
913

1014
// NewAccount creates a account controller.
11-
func NewAccount() *AccountController {
12-
return &AccountController{db: NewDB()}
15+
func NewAccount(service goa.Service) *AccountController {
16+
return &AccountController{
17+
Controller: service.NewController("Account"),
18+
db: NewDB(),
19+
}
1320
}
1421

1522
// Show retrieves the account with the given id.

examples/cellar/controllers/bottle.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
package controllers
22

3-
import "github.com/raphael/goa/examples/cellar/app"
3+
import (
4+
"github.com/raphael/goa"
5+
"github.com/raphael/goa/examples/cellar/app"
6+
)
47

58
// BottleController implements the bottle resource.
69
type BottleController struct {
10+
goa.Controller
711
db *DB
812
}
913

1014
// NewBottle creates a bottle controller.
11-
func NewBottle() *BottleController {
12-
return &BottleController{db: NewDB()}
15+
func NewBottle(service goa.Service) *BottleController {
16+
return &BottleController{
17+
Controller: service.NewController("Bottle"),
18+
db: NewDB(),
19+
}
1320
}
1421

1522
// List lists all the bottles in the account optionally filtering by year.

examples/cellar/main.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ func main() {
1919
service.Use(goa.Recover())
2020

2121
// Mount account controller onto service
22-
ac := controllers.NewAccount()
22+
ac := controllers.NewAccount(service)
2323
app.MountAccountController(service, ac)
2424

2525
// Mount bottle controller onto service
26-
bc := controllers.NewBottle()
26+
bc := controllers.NewBottle(service)
2727
app.MountBottleController(service, bc)
2828

2929
// Mount Swagger Spec controller onto service

examples/cellar/swagger/swagger.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// Generated with goagen v0.0.1, command line:
55
// $ goagen
6-
// --out=.
6+
// --out=$(GOPATH)/src/github.com/raphael/goa/examples/cellar
77
// --design=github.com/raphael/goa/examples/cellar/design
88
//
99
// The content of this file is auto-generated, DO NOT MODIFY
@@ -18,8 +18,9 @@ import (
1818

1919
// MountController mounts the swagger spec controller under "/swagger.json".
2020
func MountController(service goa.Service) {
21+
ctrl := service.NewController("Swagger")
2122
service.Info("mount", "ctrl", "Swagger", "action", "Show", "route", "GET /swagger.json")
22-
h := goa.NewHTTPRouterHandle(service, "Swagger", "Show", getSwagger)
23+
h := ctrl.NewHTTPRouterHandle("Show", getSwagger)
2324
service.HTTPHandler().(*httprouter.Router).Handle("GET", "/swagger.json", h)
2425
}
2526

goagen/gen_app/generator_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ import (
275275
276276
// WidgetController is the controller interface for the Widget actions.
277277
type WidgetController interface {
278+
goa.Controller
278279
Get(*GetWidgetContext) error
279280
}
280281
@@ -289,7 +290,7 @@ func MountWidgetController(service goa.Service, ctrl WidgetController) {
289290
}
290291
return ctrl.Get(ctx)
291292
}
292-
router.Handle("GET", "/:id", goa.NewHTTPRouterHandle(service, "Widget", "Get", h))
293+
router.Handle("GET", "/:id", ctrl.NewHTTPRouterHandle("Get", h))
293294
service.Info("mount", "ctrl", "Widget", "action", "Get", "route", "GET /:id")
294295
}
295296
`

goagen/gen_app/writers.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,7 @@ func New{{gotypename .Payload 0}}(raw interface{}) ({{gotyperef .Payload 0}}, er
433433
// template input: *ControllerTemplateData
434434
ctrlT = `// {{.Resource}}Controller is the controller interface for the {{.Resource}} actions.
435435
type {{.Resource}}Controller interface {
436+
goa.Controller
436437
{{range .Actions}} {{.Name}}(*{{.Context}}) error
437438
{{end}}}
438439
`
@@ -451,7 +452,7 @@ func Mount{{.Resource}}Controller(service goa.Service, ctrl {{.Resource}}Control
451452
}
452453
return ctrl.{{.Name}}(ctx)
453454
}
454-
{{range .Routes}} router.Handle("{{.Verb}}", "{{.FullPath}}", goa.NewHTTPRouterHandle(service, "{{$res}}", "{{$action.Name}}", h))
455+
{{range .Routes}} router.Handle("{{.Verb}}", "{{.FullPath}}", ctrl.NewHTTPRouterHandle("{{$action.Name}}", h))
455456
service.Info("mount", "ctrl", "{{$res}}", "action", "{{$action.Name}}", "route", "{{.Verb}} {{.FullPath}}")
456457
{{end}}{{end}}}
457458
`

goagen/gen_app/writers_test.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,7 @@ func NewListBottleContext(c *goa.Context) (*ListBottleContext, error) {
808808

809809
simpleController = `// BottlesController is the controller interface for the Bottles actions.
810810
type BottlesController interface {
811+
goa.Controller
811812
list(*ListBottleContext) error
812813
}
813814
`
@@ -822,13 +823,14 @@ type BottlesController interface {
822823
}
823824
return ctrl.list(ctx)
824825
}
825-
router.Handle("GET", "/accounts/:accountID/bottles", goa.NewHTTPRouterHandle(service, "Bottles", "list", h))
826+
router.Handle("GET", "/accounts/:accountID/bottles", ctrl.NewHTTPRouterHandle("list", h))
826827
service.Info("mount", "ctrl", "Bottles", "action", "list", "route", "GET /accounts/:accountID/bottles")
827828
}
828829
`
829830

830831
multiController = `// BottlesController is the controller interface for the Bottles actions.
831832
type BottlesController interface {
833+
goa.Controller
832834
list(*ListBottleContext) error
833835
show(*ShowBottleContext) error
834836
}
@@ -844,7 +846,7 @@ type BottlesController interface {
844846
}
845847
return ctrl.list(ctx)
846848
}
847-
router.Handle("GET", "/accounts/:accountID/bottles", goa.NewHTTPRouterHandle(service, "Bottles", "list", h))
849+
router.Handle("GET", "/accounts/:accountID/bottles", ctrl.NewHTTPRouterHandle("list", h))
848850
service.Info("mount", "ctrl", "Bottles", "action", "list", "route", "GET /accounts/:accountID/bottles")
849851
h = func(c *goa.Context) error {
850852
ctx, err := NewShowBottleContext(c)
@@ -853,7 +855,7 @@ type BottlesController interface {
853855
}
854856
return ctrl.show(ctx)
855857
}
856-
router.Handle("GET", "/accounts/:accountID/bottles/:id", goa.NewHTTPRouterHandle(service, "Bottles", "show", h))
858+
router.Handle("GET", "/accounts/:accountID/bottles/:id", ctrl.NewHTTPRouterHandle("show", h))
857859
service.Info("mount", "ctrl", "Bottles", "action", "show", "route", "GET /accounts/:accountID/bottles/:id")
858860
}
859861
`

goagen/gen_main/generator.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,13 @@ func main() {
237237
}
238238
`
239239
const ctrlTmpl = `// {{$ctrlName := printf "%s%s" (goify .Name true) "Controller"}}{{$ctrlName}} implements the {{.Name}} resource.
240-
type {{$ctrlName}} struct {}
240+
type {{$ctrlName}} struct {
241+
goa.Controller
242+
}
241243
242244
// New{{$ctrlName}} creates a {{.Name}} controller.
243-
func New{{$ctrlName}}() *{{$ctrlName}} {
244-
return &{{$ctrlName}}{}
245+
func New{{$ctrlName}}(service goa.Service) {{$ctrlName}} {
246+
return &{{$ctrlName}}{Controller: service.NewController("{{$ctrlName}}")}
245247
}
246248
{{$ctrl := .}}{{range .Actions}}
247249
// {{goify .Name true}} runs the {{.Name}} action.

goagen/gen_swagger/generator.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,9 @@ func Generate(api *design.APIDefinition) ([]string, error) {
6868
const swaggerTmpl = `
6969
// MountController mounts the swagger spec controller under "/swagger.json".
7070
func MountController(service goa.Service) {
71+
ctrl := service.NewController("Swagger")
7172
service.Info("mount", "ctrl", "Swagger", "action", "Show", "route", "GET /swagger.json")
72-
h := goa.NewHTTPRouterHandle(service, "Swagger", "Show", getSwagger)
73+
h := ctrl.NewHTTPRouterHandle("Show", getSwagger)
7374
service.HTTPHandler().(*httprouter.Router).Handle("GET", "/swagger.json", h)
7475
}
7576

0 commit comments

Comments
 (0)