How to implement MVC in Go

Go makes programming fun again.

Go programming language (Golang) is a high performance programming language. It’s developed by experts working in Google. Go is powerful yet beautiful language that worth to learn, especially if you have experience in C or PHP. In short, Go makes programming fun again.

In this short post, I will show some code snippets to give overview of how to program in Go using Model View and Controller (MVC) pattern.

Firstly, it is important to know the flow of HTTP request and response.

Here is the flow of request:

Browser -> Request -> Route -> (Middleware/opt)-> Controller -> Model -> Database Query

And here’s the flow of response:

Query Result -> Model -> Controller -> View -> Response -> Browser

Next, we will start exploring the backend code.

For example, we will create a simple Notes App.

First, we want to read our note list at http://localhost/notepad. So we design our route as follow:

<br />
r.GET("/notepad", hr.Handler(alice.<br />
New(acl.DisallowAnon).<br />
ThenFunc(controller.NotepadReadGET)))<br />

So if our app receive a request at this URL, then we will call a acl.DisallowAnon middleware and then call controller.NotepadReadGET. DisallowAnon function within the acl package is a middleware that checks user session. If the user has logged in, then user will be allowed to continue the process (go to NotepadReadGET method), otherwise, user will not be able to access the page.

</p>
<p>// DisallowAnon does not allow anonymous users to access the page<br />
func DisallowAnon(h http.Handler) http.Handler {<br />
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {<br />
// Get session<br />
sess := session.Instance(r)</p>
<p>// If user is not authenticated, don't allow them to access the page<br />
if sess.Values["id"] == nil {<br />
http.Redirect(w, r, "/", http.StatusFound)<br />
return<br />
}</p>
<p>h.ServeHTTP(w, r)<br />
})<br />
}<br />

Upon successful, the app will call a NotepadReadGET controller.

</p>
<p>// NotepadReadGET displays the notes in the notepad<br />
func NotepadReadGET(w http.ResponseWriter, r *http.Request) {<br />
// Get session<br />
sess := session.Instance(r)</p>
<p>userID := fmt.Sprintf("%s", sess.Values["id"])</p>
<p>notes, err := model.NotesByUserID(userID)<br />
if err != nil {<br />
log.Println(err)<br />
notes = []model.Note{}<br />
}</p>
<p>// Display the view<br />
v := view.New(r)<br />
v.Name = "notepad/read"<br />
v.Vars["first_name"] = sess.Values["first_name"]<br />
v.Vars["notes"] = notes<br />
v.Render(w)<br />
}<br />

This controller call another function in model package, named model.NotesByUserID(userID). This function takes userID as its parameter. Here’s the code of NotesByUserID

<br />
// NotesByUserID gets all notes for a user</p>
<p>func NotesByUserID(userID string) ([]Note, error) {</p>
<p>var err error</p>
<p>var result []Note</p>
<p>err = database.SQL.Select(&result, "SELECT id, content, user_id, created_at, updated_at, deleted FROM note WHERE user_id = ?", userID)</p>
<p>return result, standardizeError(err)</p>
<p>}</p>
<p>

This model will execute a query selecting all notes of this user and return the results and the error message (if any).

Next, the result will be served as HTML page using notepad/read template:

<h1>{{.first_name}}'s Notepad</h1>
</div>
<a title="Add Note" class="btn btn-primary" role="button" href="{{$.BaseURI}}notepad/create">
<span class="fa fa-plus" aria-hidden="true"></span> Add Note
</a>

{{range $n := .notes}}
<div class="panel panel-default">
<div class="panel-body">

{{.Content}}
<div style="display: inline-block;">
            <a title="Edit Note" class="btn btn-warning" role="button" href="{{$.BaseURI}}notepad/update/{{.NoteID}}">
<span class="fa fa-edit" aria-hidden="true"></span> Edit
</a>
<a title="Delete Note" class="btn btn-danger" role="button" href="{{$.BaseURI}}notepad/delete/{{.NoteID}}">
<span class="fa fa-trash" aria-hidden="true"></span> Delete
</a></div>
<span class="pull-right" style="margin-top: 14px;">{{.UpdatedAt | PRETTYTIME}}</span></div>
</div>
{{end}}

And finally, the page will show the following result

Easy, isn’t it?

Happy coding!

Please follow and like us: