# 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. ## Beego the REST design Previous section describes the routing function to achieve a registered struct, and the struct implements REST approach, so we need to design a controller for logic processing base class, where the main design of the two types, a struct, an interface 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 function described earlier, when a route is defined ControllerInterface type, so long as we can implement this interface, so our base class Controller to achieve the following methods: 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) } At the controller base class already implements the interface defined functions performed by routing the appropriate controller according url principles will be followed by implementation of the following: Init() initializes Prepare() before the execution of the initialization, each subclass can inherit to implement the function method() depending on the method to perform different functions: GET, POST, PUT, HEAD, etc. sub-classes to implement these functions, if not achieved, then the default is 403 Render() optional, according to a global variable to determine whether to execute AutoRender Finish() after the implementation of the action, each subclass inherits the function can be achieved ## Application guide Above beego Framework base class to complete the design of the controller, then we in our application can be to design our approach: 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" } The way we achieved above subclass MainController, implements Get method, so if the user through other means(POST/HEAD, etc. ) to access the resource will return 403, and if it is Get access, because we set the AutoRender = true, then play in the implementation of the Get method is performed automatically after the Render function, it will display the following interface: ![](images/13.4.beego.png?raw=true) index.tpl code is shown below, we can see the data set and display are quite simple: beego welcome template

Hello, world!{{.Username}},{{.Email}}

## Links - [Directory](preface.md) - Previous section: [Customized routers](13.2.md) - Next section: [Logs and configurations](13.4.md)