# 13.3 Designing controllers Most traditional MVC frameworks are based on suffix action mapping. Nowadays, the REST style web architecture is becoming increasingly popular. One can implement REST-style URLs by filtering or rewriting them, but why not just design a new REST-style MVC framework instead? This section is based on this idea, and focusses on designing and implementing a controller based, REST-style MVC framework from scratch. Our goal is to simplify the development of web applications, perhaps even allowing us to write a single line of code capable of serving "Hello, world". ## The controller's role The MVC design pattern is currently the most used framework model for web applications. By keeping Models, Views and Controllers separated, we can keep our web applications modular, maintainable, testable and extensible. A model encapsulates data and any of the business logic that governs that data, such as accessibility rules, persistence, validation, etc. Views serve as the data's representation and in the case of web applications, they usually live as templates which are then rendered into HTML and served. Controllers serve as the "glue" logic between Models and Views and typically have methods for handling different URLs. As described in the previous section, when a URL request is forwarded to a controller by the router, the controller delegates commands to the Model to perform some action, then notifies the View of any changes. In certain cases, there is no need for models to perform any kind of logical or data processing, or for any views to be rendered. For instance, in the case of an HTTP 302 redirect, no view needs to be rendered and no processing needs to be performed by the Model, however the Controller's job is still essential. ## RESTful design in Beego The previous section describes registering route handlers with RESTful structs. Now, we need to design the base class for a logic controller that will be composed of two parts: a struct and interface type. type Controller struct { Ct *Context Tpl *template.Template Data map[interface{}]interface{} ChildName string TplNames string Layout []string TplExt string } type ControllerInterface interface { Init(ct *Context, cn string) //Initialize the context and subclass name Prepare() //some processing before execution begins Get() //method = GET processing Post() //method = POST processing Delete() //method = DELETE processing Put() //method = PUT handling Head() //method = HEAD processing Patch() //method = PATCH treatment Options() //method = OPTIONS processing Finish() //executed after completion of treatment Render() error //method executed after the corresponding method to render the page } Then add the route handling function described earlier in this chapter. When a route is defined to be a `ControllerInterface` type, so long as we can implement this interface, we can have access to the following methods of our base class controller. func (c *Controller) Init(ct *Context, cn string) { c.Data = make(map[interface{}]interface{}) c.Layout = make([]string, 0) c.TplNames = "" c.ChildName = cn c.Ct = ct c.TplExt = "tpl" } func (c *Controller) Prepare() { } func (c *Controller) Finish() { } func (c *Controller) Get() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } func (c *Controller) Post() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } func (c *Controller) Delete() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } func (c *Controller) Put() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } func (c *Controller) Head() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } func (c *Controller) Patch() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } func (c *Controller) Options() { http.Error(c.Ct.ResponseWriter, "Method Not Allowed", 405) } func (c *Controller) Render() error { if len(c.Layout) > 0 { var filenames []string for _, file := range c.Layout { filenames = append(filenames, path.Join(ViewsPath, file)) } t, err := template.ParseFiles(filenames...) if err != nil { Trace("template ParseFiles err:", err) } err = t.ExecuteTemplate(c.Ct.ResponseWriter, c.TplNames, c.Data) if err != nil { Trace("template Execute err:", err) } } else { if c.TplNames == "" { c.TplNames = c.ChildName + "/" + c.Ct.Request.Method + "." + c.TplExt } t, err := template.ParseFiles(path.Join(ViewsPath, c.TplNames)) if err != nil { Trace("template ParseFiles err:", err) } err = t.Execute(c.Ct.ResponseWriter, c.Data) if err != nil { Trace("template Execute err:", err) } } return nil } func (c *Controller) Redirect(url string, code int) { c.Ct.Redirect(code, url) } Above, the controller base class already implements the functions defined in the interface. Through our routing rules, the request will be routed to the appropriate controller which will in turn execute the following methods: Init() initialization routine Prepare() pre-initialization routine; each inheritting subclass may implement this function method() depending on the request method, perform different functions: GET, POST, PUT, HEAD, etc. Subclasses should implement these functions; if not implemented, then the default is 403 Render() optional method. Determine whether or not to execute according to the global variable "AutoRender" Finish() is executed after the action been completed. Each inheritting subclass may implement this function ## Application guide Above, we've just finished discussing Beego's implementation of the base controller class. We can now use this information to design our request handling, inheriting from the base class and implementing the necessary methods in our own controller. package controllers import ( "github.com/astaxie/beego" ) type MainController struct { beego.Controller } func (this *MainController) Get() { this.Data["Username"] = "astaxie" this.Data["Email"] = "astaxie@gmail.com" this.TplNames = "index.tpl" } In the code above, we've implemented a subclass of `Controller` called `MainController` which only implements the `Get()` method. If a user tries to access the resource using any of the other HTTP methods (POST, HEAD, etc), a 403 Forbidden will be returned. However, if a user submits a GET request to the resource and we have have the `AutoRender` variable set to `true`, the resource's controller will automatically call its `Render()` function, rendering the corresponding template and responding with the following:  The `index.tpl` code can be seen below; as you can see, parsing model data into a template is quite simple: