Building a Go Web Application with the Buffalo Framework

Table of Contents

  1. Introduction
  2. Prerequisites
  3. Installation
  4. Creating a New Buffalo Project
  5. Building the Web Application
  6. Adding Routes and Handlers
  7. Creating Views and Templates
  8. Working with Models and Database
  9. Testing the Web Application
  10. Conclusion


Introduction

In this tutorial, we will learn how to build a Go web application using the Buffalo framework. Buffalo is a highly productive web framework that follows the convention over configuration principle, allowing developers to focus on writing business logic instead of spending time on setting up the project structure. By the end of this tutorial, you will have a basic understanding of Buffalo and its core components, such as routes, handlers, views, and models.

Prerequisites

To follow along with this tutorial, you should have a basic understanding of the Go programming language. You will also need to have Go installed on your machine. If you haven’t installed Go yet, please refer to the official Go website (https://golang.org/doc/install) for instructions on how to install it.

Installation

Before we can start building our web application, we need to install Buffalo. Open your terminal or command prompt and run the following command to install Buffalo:

go get -u github.com/gobuffalo/buffalo/buffalo

Once the installation is complete, you can verify that Buffalo is installed correctly by running the following command:

buffalo version

If everything is set up correctly, you should see the version number of Buffalo printed in the console.

Creating a New Buffalo Project

Now that Buffalo is installed, let’s create a new project. In your terminal, navigate to the directory where you want to create the project and run the following command:

buffalo new myapp

This command will create a new Buffalo project named “myapp” in a directory called “myapp” as well. Change your current directory to the newly created project:

cd myapp

Building the Web Application

Now, let’s build our web application. Buffalo provides a built-in development server that makes it easy to preview our application as we develop it. To start the development server, run the following command:

buffalo dev

Buffalo will start the server and print the URL where you can access your application in the console. Open your web browser and visit the provided URL. You should see a default welcome page.

Adding Routes and Handlers

In Buffalo, routes are defined in the routes folder in a file named app.go. Let’s add a new route that maps to a handler function. Open the app.go file and add the following code:

package actions

import (
	"github.com/gobuffalo/buffalo"
)

func init() {
	app.GET("/", HomeHandler)
}

func HomeHandler(c buffalo.Context) error {
	return c.Render(200, r.HTML("index.html"))
}

In this code, we define a new route that maps the root URL (“/”) to the HomeHandler function. The HomeHandler function renders the index.html template.

Creating Views and Templates

Buffalo uses the Plush templating engine to render views. Views and templates are stored in the templates folder. Let’s create a simple index.html template. Create a new file named index.html in the templates folder with the following content:

<h1>Welcome to myapp!</h1>
<p>This is the default home page.</p>

Now, if you refresh your browser, you should see the content of your index.html template rendered.

Working with Models and Database

Buffalo comes with a built-in ORM (Object-Relational Mapping) library called Pop. This allows us to work with databases easily. Let’s create a simple model and perform CRUD (Create, Read, Update, Delete) operations.

First, let’s create a new model. Run the following command to generate a new model file:

buffalo g model todo title content

This command will generate a new model file named todo.go in the models folder. Open the todo.go file and modify it as follows:

package models

import (
	"github.com/gobuffalo/buffalo"
	"github.com/gobuffalo/pop/v5"
	"github.com/pkg/errors"
)

type Todo struct {
	ID      int    `json:"id" db:"id"`
	Title   string `json:"title" db:"title"`
	Content string `json:"content" db:"content"`
}

func (t Todo) Create(c buffalo.Context) error {
	if err := c.Bind(&t); err != nil {
		return errors.WithStack(err)
	}

	tx, ok := c.Value("tx").(*pop.Connection)
	if !ok {
		return errors.WithStack(errors.New("no transaction found"))
	}

	verrs, err := tx.ValidateAndCreate(&t)
	if err != nil {
		return errors.WithStack(err)
	}

	if verrs.HasAny() {
		// handle validation errors
	}

	return c.Render(200, r.JSON(t))
}

func (t Todo) List(c buffalo.Context) error {
	tx, ok := c.Value("tx").(*pop.Connection)
	if !ok {
		return errors.WithStack(errors.New("no transaction found"))
	}

	todos := []Todo{}
	if err := tx.All(&todos); err != nil {
		return errors.WithStack(err)
	}

	return c.Render(200, r.JSON(todos))
}

In this code, we define a Todo struct as our model and add Create and List methods. The Create method handles creating a new todo item, and the List method retrieves all todo items from the database.

To generate the migrations and update the database schema, run the following command:

buffalo db migrate

This command will create a new migration file and apply it to the database.

To create a route for our new model’s actions, open the app.go file and modify it as follows:

package actions

import (
	"github.com/gobuffalo/buffalo"
	"github.com/your-username/myapp/models"
)

// ...

func init() {
	app.GET("/", HomeHandler)
	app.POST("/todos", models.Todo{}.Create) // Add this line
	app.GET("/todos", models.Todo{}.List)   // Add this line
}

We have added two new routes—one for creating a todo item (POST /todos) and another for listing all todo items (GET /todos).

Testing the Web Application

Buffalo provides a testing framework to help us write tests for our web application easily. Let’s create a basic test for our todo endpoints.

Create a new file named todo_test.go in the actions folder and add the following code:

package actions

import (
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gobuffalo/buffalo"
	"github.com/your-username/myapp/models"
	"github.com/stretchr/testify/require"
)

func TestTodoCreate(t *testing.T) {
	app := buffalo.New(buffalo.Options{})
	app.POST("/todos", models.Todo{}.Create)

	w := httptest.NewRecorder()
	req := httptest.NewRequest(http.MethodPost, "/todos", nil)
	c := app.NewContext(req, w)

	err := models.DB.TruncateAll()
	require.NoError(t, err)

	res := app.ServeHTTP(c)
	require.Equal(t, 200, res.Code)

	// Assert the response here
}

func TestTodoList(t *testing.T) {
	app := buffalo.New(buffalo.Options{})
	app.GET("/todos", models.Todo{}.List)

	w := httptest.NewRecorder()
	req := httptest.NewRequest(http.MethodGet, "/todos", nil)
	c := app.NewContext(req, w)

	err := models.DB.TruncateAll()
	require.NoError(t, err)

	res := app.ServeHTTP(c)
	require.Equal(t, 200, res.Code)

	// Assert the response here
}

In these tests, we create a new Buffalo application, define routes for the todo endpoints, and send test requests to these endpoints. We then assert the expected responses.

To run the tests, execute the following command:

buffalo test ./...

This command will run all tests in the current project directory and its subdirectories.

Conclusion

Congratulations! You have built a simple Go web application using the Buffalo framework. In this tutorial, we covered the basics of Buffalo, including setting up a new project, building routes, handling requests and responses, working with views and templates, using models and the database, and writing tests.

Buffalo provides many more features and options for building robust web applications. I encourage you to explore the Buffalo documentation (https://gobuffalo.io) to learn more about its capabilities and best practices.

Remember to experiment with different features and expand your application according to your needs. Happy coding!