Go Buffalo – Rapid Web Development

When you want to create a rest service or web application in Go, you have to do a lot of work around project setup, application architecture, directory structures, and more. What if there was a web development platform that already has everything from front-end (JavaScript, CSS) to back-end (database, routing), designed to make the life of a Go web developer easier. Well, there is, it is called Buffalo. Lets take a look!

Buffalo

Buffalo is a web application development environment for Go, inspired by Ruby on Rails, the Play Framework, Django and other rapid application web frameworks. Buffalo makes use of the Gorilla toolkit, a web toolkit for Go.

Install

Buffalo can be installed by typing:

<span style="color:#998;font-style:italic"># from source with sqlite3 support</span>
go get -u -v -tags sqlite github.com/gobuffalo/buffalo/buffalo

<span style="color:#998;font-style:italic"># from source *without* sqlite3 support</span>
go get -u -v github.com/gobuffalo/buffalo-plugins

<span style="color:#998;font-style:italic"># using homebrew</span>
$ brew install gobuffalo/tap/buffalo

After installation you should have the buffalo cli installed:

$ buffalo version
INFO<span style="font-weight:bold">[</span>0000<span style="font-weight:bold">]</span> Buffalo version is: v0.13.7

A REST API

Buffalo can also create simple REST APIs. Buffalo v0.13.7 does not support modules, so you have to create a directory in $GOPATH eg. $GOPATH/src/github.com/binxio/blog-go-buffalo and type the following

$ buffalo new go_blog_buffalo --api --skip-pop
$ <span style="color:#999">cd</span> go_blog_buffalo
$ buffalo dev
buffalo: 2018/11/27 19:16:41 <span style="font-weight:bold">=</span><span style="font-weight:bold">=</span><span style="font-weight:bold">=</span> Rebuild on: :start: <span style="font-weight:bold">=</span><span style="font-weight:bold">=</span><span style="font-weight:bold">=</span>
buffalo: 2018/11/27 19:16:41 <span style="font-weight:bold">=</span><span style="font-weight:bold">=</span><span style="font-weight:bold">=</span> Running: go build -v -i -tags development -o tmp/go-buffalo-build  <span style="font-weight:bold">(</span>PID: 17379<span style="font-weight:bold">)</span> <span style="font-weight:bold">=</span><span style="font-weight:bold">=</span><span style="font-weight:bold">=</span>
buffalo: 2018/11/27 19:16:42 <span style="font-weight:bold">=</span><span style="font-weight:bold">=</span><span style="font-weight:bold">=</span> Building Completed <span style="font-weight:bold">(</span>PID: 17379<span style="font-weight:bold">)</span> <span style="font-weight:bold">(</span>Time: 1.322165735s<span style="font-weight:bold">)</span> <span style="font-weight:bold">=</span><span style="font-weight:bold">=</span><span style="font-weight:bold">=</span>
buffalo: 2018/11/27 19:16:42 <span style="font-weight:bold">=</span><span style="font-weight:bold">=</span><span style="font-weight:bold">=</span> Running: tmp/go-buffalo-build <span style="font-weight:bold">(</span>PID: 17397<span style="font-weight:bold">)</span> <span style="font-weight:bold">=</span><span style="font-weight:bold">=</span><span style="font-weight:bold">=</span>
INFO<span style="font-weight:bold">[</span>2018-11-27T19:16:45+01:00<span style="font-weight:bold">]</span> Starting application at 127.0.0.1:3000
INFO<span style="font-weight:bold">[</span>2018-11-27T19:16:45+01:00<span style="font-weight:bold">]</span> Starting Simple Background Worker

The service is available at port ‘3000’:

$ http :3000
HTTP/1.1 <span style="color:#099">200</span> OK
Content-Length: <span style="color:#099">34</span>
Content-Type: application/json
Date: Tue, <span style="color:#099">27</span> Nov <span style="color:#099">2018</span> 18:17:36 GMT
Vary: Origin

<span style="font-weight:bold">{</span>
    <span style="color:#b84">"message"</span>: <span style="color:#b84">"Welcome to Buffalo!"</span>
<span style="font-weight:bold">}</span>

Generator

Buffalo comes with a generator that can generate Actions. Lets start a second terminal, navigate to $GOPATH/src/github.com/binxio/blog-go-buffalo and type:

$ buffalo g a cats List --skip-template

The generator has created a cats.go file with the CatsList action.

Change the following lines in app.go:

<span style="color:#998;font-style:italic">// change this line
</span><span style="color:#998;font-style:italic"></span>app.<span style="color:#900;font-weight:bold">GET</span>(<span style="color:#b84">"/cats/List"</span>, CatsList)

<span style="color:#998;font-style:italic">// to this line
</span><span style="color:#998;font-style:italic"></span>app.<span style="color:#900;font-weight:bold">GET</span>(<span style="color:#b84">"/cats"</span>, CatsList)

Notice that Buffalo automatically compiles and reloads the server to reflect the changes to the application.

Lets implement the CatsList handler in cats.go:

<span style="font-weight:bold">package</span> actions

<span style="font-weight:bold">import</span> <span style="color:#b84">"github.com/gobuffalo/buffalo"</span>

<span style="font-weight:bold">type</span> Cat <span style="font-weight:bold">struct</span> {
    Name <span style="color:#458;font-weight:bold">string</span> <span style="color:#b84">`</span><span style="color:#b84">json:"name"</span><span style="color:#b84">`</span>
    Age <span style="color:#458;font-weight:bold">int</span> <span style="color:#b84">`</span><span style="color:#b84">json:"age"</span><span style="color:#b84">`</span>
}

<span style="font-weight:bold">var</span> cats = []Cat {
    Cat { Name: <span style="color:#b84">"Elsa"</span>, Age: <span style="color:#099">16</span> },
    Cat { Name: <span style="color:#b84">"Tijger"</span>, Age: <span style="color:#099">12</span> },
}

<span style="color:#998;font-style:italic">// CatsList default implementation.
</span><span style="color:#998;font-style:italic"></span><span style="font-weight:bold">func</span> <span style="color:#900;font-weight:bold">CatsList</span>(c buffalo.Context) <span style="color:#458;font-weight:bold">error</span> {
    <span style="font-weight:bold">return</span> c.<span style="color:#900;font-weight:bold">Render</span>(<span style="color:#099">200</span>, r.<span style="color:#900;font-weight:bold">JSON</span>(cats))
}

Call the endpoint:

$ http :3000/cats
HTTP/1.1 <span style="color:#099">200</span> OK
Content-Length: <span style="color:#099">54</span>
Content-Type: application/json
Date: Tue, <span style="color:#099">27</span> Nov <span style="color:#099">2018</span> 18:42:38 GMT
Vary: Origin

<span style="font-weight:bold">[</span>
    <span style="font-weight:bold">{</span>
        <span style="color:#b84">"age"</span>: 16,
        <span style="color:#b84">"name"</span>: <span style="color:#b84">"Elsa"</span>
    <span style="font-weight:bold">}</span>,
    <span style="font-weight:bold">{</span>
        <span style="color:#b84">"age"</span>: 12,
        <span style="color:#b84">"name"</span>: <span style="color:#b84">"Tijger"</span>
    <span style="font-weight:bold">}</span>
<span style="font-weight:bold">]</span>

Lets add a new route with the command:

$ buffalo g a cats GetById --skip-template

Change the following lines in app.go:

<span style="color:#998;font-style:italic">// change this line
</span><span style="color:#998;font-style:italic"></span>app.<span style="color:#900;font-weight:bold">GET</span>(<span style="color:#b84">"/cats/GetById"</span>, CatsGetByID)

<span style="color:#998;font-style:italic">// to this line
</span><span style="color:#998;font-style:italic"></span>app.<span style="color:#900;font-weight:bold">GET</span>(<span style="color:#b84">"/cats/{id:[0-9]+}"</span>, CatsGetByID)

Add the following implementation to cats.go:

<span style="font-weight:bold">package</span> actions

<span style="font-weight:bold">import</span> (
    <span style="color:#b84">"github.com/gobuffalo/buffalo"</span>
    <span style="color:#b84">"github.com/gorilla/mux"</span>
    <span style="color:#b84">"net/http"</span>
    <span style="color:#b84">"strconv"</span>
)

<span style="font-weight:bold">type</span> Cat <span style="font-weight:bold">struct</span> {
    ID <span style="color:#458;font-weight:bold">int</span> <span style="color:#b84">`</span><span style="color:#b84">json:"id"</span><span style="color:#b84">`</span>
    Name <span style="color:#458;font-weight:bold">string</span> <span style="color:#b84">`</span><span style="color:#b84">json:"name"</span><span style="color:#b84">`</span>
    Age  <span style="color:#458;font-weight:bold">int</span>    <span style="color:#b84">`</span><span style="color:#b84">json:"age"</span><span style="color:#b84">`</span>
}

<span style="font-weight:bold">var</span> cats = []Cat{
    Cat{ID: <span style="color:#099">1</span>, Name: <span style="color:#b84">"Elsa"</span>, Age: <span style="color:#099">16</span>},
    Cat{ID: <span style="color:#099">2</span>, Name: <span style="color:#b84">"Tijger"</span>, Age: <span style="color:#099">12</span>},
}

<span style="font-weight:bold">func</span> <span style="color:#900;font-weight:bold">CatsList</span>(c buffalo.Context) <span style="color:#458;font-weight:bold">error</span> {
    <span style="font-weight:bold">return</span> c.<span style="color:#900;font-weight:bold">Render</span>(http.StatusOK, r.<span style="color:#900;font-weight:bold">JSON</span>(cats))
}

<span style="font-weight:bold">func</span> <span style="color:#900;font-weight:bold">CatsGetByID</span>(c buffalo.Context) <span style="color:#458;font-weight:bold">error</span> {
    params <span style="font-weight:bold">:=</span> mux.<span style="color:#900;font-weight:bold">Vars</span>(c.<span style="color:#900;font-weight:bold">Request</span>())
    id, _ <span style="font-weight:bold">:=</span> strconv.<span style="color:#900;font-weight:bold">Atoi</span>(params[<span style="color:#b84">"id"</span>])
    <span style="font-weight:bold">for</span> _, cat <span style="font-weight:bold">:=</span> <span style="font-weight:bold">range</span> cats {
        <span style="font-weight:bold">if</span> cat.ID <span style="font-weight:bold">==</span> id {
            <span style="font-weight:bold">return</span> c.<span style="color:#900;font-weight:bold">Render</span>(http.StatusOK, r.<span style="color:#900;font-weight:bold">JSON</span>(cat))
        }
    }
    <span style="font-weight:bold">return</span> c.<span style="color:#900;font-weight:bold">Render</span>(http.StatusNotFound, <span style="font-weight:bold">nil</span>)
}

And call the endpoint:

$ http :3000/cats/1
HTTP/1.1 <span style="color:#099">200</span> OK
Content-Length: <span style="color:#099">32</span>
Content-Type: application/json
Date: Tue, <span style="color:#099">27</span> Nov <span style="color:#099">2018</span> 18:51:09 GMT
Vary: Origin

<span style="font-weight:bold">{</span>
    <span style="color:#b84">"age"</span>: 16,
    <span style="color:#b84">"id"</span>: 1,
    <span style="color:#b84">"name"</span>: <span style="color:#b84">"Elsa"</span>
<span style="font-weight:bold">}</span>

Conclusion

Buffalo makes it really easy to create rest services. Buffalo creates a project skeleton, generates actions and templates, runs the server and provides hot reload on code change. We have created two actions, one for cats and one to get a cat by id. Buffalo makes use of the Gorilla toolkit what makes it easy for us to extend the REST service with functionality. I will definitely use Buffalo for a next project.

Share this article: Tweet this post / Post on LinkedIn