Setup nested HTML template in Go Echo web framework
Tags: go, echo
Published: 2018-11-20 16:49:41

---
title: Setup nested HTML template in Go Echo web framework
published: true
description: "Remove duplicated html codes by manipulating nested HTML templates provided Go standard library."
tags: [Golang, Echo]
cover_image: https://thepracticaldev.s3.amazonaws.com/i/4bak0es65o5z5zoccqjh.png
---

_Originally posted on [Boatswain Blog](https://blog.boatswain.io/post/setup-nested-html-template-in-go-echo-web-framework/)._

---

[Echo][echo] is a lightweight but complete web framework in [Go][golang] for building RESTful API. It is fast and includes a bunch of middleware for handling the whole HTTP request-response cycle. For the rendering part, it works with any template engine but i pick the standard [html/template][html/template] package for the purpose of simplicity. And at the end of this article, a nested template [Echo][echo] project setup is demonstrated.

If you already have an idea on how [Echo][echo] works, jump to the [Using nested template section](https://blog.boatswain.io/post/setup-nested-html-template-in-go-echo-web-framework/#using-nested-template).

## A basic Echo project setup

### Create the project folder under proper $GOPATH

The complete project code is hosted on [GitLab](https://gitlab.com/ykyuen/golang-echo-template-example) so we first create the project folder _$GOPATH/src/gitlab.com/ykyuen/golang-echo-template-example_.

### Create the _main.go_

Inside the newly created folder, let's just copy the hello world example from the [Echo][echo] official site and create the _main.go_.

_main.go_

```go
package main

import (
  "net/http"

  "github.com/labstack/echo"
)

func main() {
  e := echo.New()
  e.GET("/", func(c echo.Context) error {
    return c.String(http.StatusOK, "Hello, World!")
  })
  e.Logger.Fatal(e.Start(":1323"))
}
```

### Download the Echo package using dep

Simply run **dep init** if [dep][dep] is installed. You can refer to this post for more information about [dep][dep].

- [Manage Go dependencies using dep](https://blog.boatswain.io/post/manage-go-dependencies-using-dep/)

Or run **go get github.com/labstack/echo** to download the [Echo][echo] package in _$GOPATH_.

### Run the hello world

Start the application by **go run main.go** and then visit http://localhost:1323 thru browser or the **curl** command.

![Start the Echo server.](https://thepracticaldev.s3.amazonaws.com/i/fkb9i9msht4v3s2ostpb.jpg)

![Send a request and get the hello world.](https://thepracticaldev.s3.amazonaws.com/i/t7ieyy30ww2hjhyqvzwy.jpg)

## Return a JSON response

When building a RESTful API, it is more likely that the client wants to receive and JSON response instead of a string. Let's write some [Go][golang] code in _main.go_.

_main.go_

```go
package main

import (
  "net/http"

  "github.com/labstack/echo"
)

func main() {
  e := echo.New()

  e.GET("/", func(c echo.Context) error {
    return c.String(http.StatusOK, "Hello, World!")
  })

  e.GET("/json", func(c echo.Context) error {
    return c.JSONBlob(
      http.StatusOK,
      []byte(`{ "id": "1", "msg": "Hello, Boatswain!" }`),
    )
  })

  e.Logger.Fatal(e.Start(":1323"))
}
```

## Return an HTML

Similar to returning a JSON object, we just need to call another method in the **return** statement.

_main.go_

```go
package main

import (
  "net/http"

  "github.com/labstack/echo"
)

func main() {
  e := echo.New()

  e.GET("/", func(c echo.Context) error {
    return c.String(http.StatusOK, "Hello, World!")
  })

  e.GET("/json", func(c echo.Context) error {
    return c.JSONBlob(
      http.StatusOK,
      []byte(`{ "id": "1", "msg": "Hello, Boatswain!" }`),
    )
  })

  e.GET("/html", func(c echo.Context) error {
    return c.HTML(
      http.StatusOK,
      "<h1>Hello, Boatswain!</h1>",
    )
  })

  e.Logger.Fatal(e.Start(":1323"))
}
```

The above are just two simple examples, [Echo][echo] has a few more convenient ways to return JSON and HTML. For details please refer to the [documentation](https://echo.labstack.com/guide/response).

### Render HTML using template engine

As mentioned at the very beginning, we could implement template engine when returning the HTTP response but before that, let's restructure the project as follow.

```bash
golang-echo-template-example/
  ├── handler/             # folder of request handlers
  │   └── home_handler.go
  ├── vendor/              # dependencies managed by dep
  │   ├── github.com/*
  │   └── golang.org/*
  ├── view/                # folder of html templates
  │   └── home.html
  ├── Gopkg.lock           # dep config file
  ├── Gopkg.toml           # dep config file
  └── main.go              # programme entrypoint
```

_main.go_

```go
package main

import (
  "html/template"
  "io"

  "github.com/labstack/echo"

  "gitlab.com/ykyuen/golang-echo-template-example/handler"
)

// Define the template registry struct
type TemplateRegistry struct {
  templates *template.Template
}

// Implement e.Renderer interface
func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
  return t.templates.ExecuteTemplate(w, name, data)
}

func main() {
  // Echo instance
  e := echo.New()

  // Instantiate a template registry and register all html files inside the view folder
  e.Renderer = &TemplateRegistry{
    templates: template.Must(template.ParseGlob("view/*.html")),
  }

  // Route => handler
  e.GET("/", handler.HomeHandler)

  // Start the Echo server
  e.Logger.Fatal(e.Start(":1323"))
}
```

In this _main.go_, we define a type called **TemplateRegistry** and implement the **[Renderer](https://godoc.org/github.com/labstack/echo#Renderer)** interface. A **Renderer** is a simple interface which wraps the **Render()** function. Inside a **TemplateRegistry** instance, it has a **templates** field containing all the templates needed for the [Echo][echo] server to render html response and this is configured in the **main()** flow.

On the other hand, we define the **HomeHandler** in order to keep the logic in separate file.

_handler/home_handler.go_

```go
package handler

import (
  "net/http"

  "github.com/labstack/echo"
)

func HomeHandler(c echo.Context) error {
  // Please note the the second parameter "home.html" is the template name and should
  // be equal to the value stated in the {{ define }} statement in "view/home.html"
  return c.Render(http.StatusOK, "home.html", map[string]interface{}{
    "name": "HOME",
    "msg": "Hello, Boatswain!",
  })
}
```

When the **c.Render()** is invoked, it executes the template which is already set in our **TemplateRegistry** instance as stated in **main.go**. The three paramaters are

1. HTTP response code
1. The template name
1. The data object which could be used in the template

_view/home.html_

```html
{{define "home.html"}}
  <!DOCTYPE html>
  <html>
    <head>
      <title>Boatswain Blog | {{index . "name"}}</title>
    </head>
    <body>
      <h1>{{index . "msg"}}</h1>
    </body>
  </html>
{{end}}
```

This above template is named as **home.html** as stated in the **define** statement and it could read the **name** and **msg** strings from **c.Render()** for the **&lt;title&gt;** and **&lt;h1&gt;** tags.

### Using nested template

In the above setup, every HTML template has a complete set of HTML code and many of them are duplicated. Using nested template makes it easier to maintain the project. Originally the **templates** field in the **TemplateRegistry** contains all the templates files. In the new setup, we make it into an **map** field and each item is a single set of template files for a particular HTML page.

We add a few files to the project and it should look like this.

```bash
golang-echo-template-example/
  ├── handler/              # folder of request handlers
  │   ├── home_handler.go   # handler for home page
  │   └── about_handler.go  # handler for about page
  ├── vendor/               # dependencies managed by dep
  │   ├── github.com/*
  │   └── golang.org/*
  ├── view/                 # folder of html templates
  │   ├── base.html         # base layout template
  │   ├── home.html         # home page template
  │   └── about.html        # about page template
  ├── Gopkg.lock            # dep config file
  ├── Gopkg.toml            # dep config file
  └── main.go               # programme entrypoint
```

The codes below are based on this [gist](https://gist.github.com/rand99/808e6e9702c00ce64803d94abff65678) created by [rand99](https://gist.github.com/rand99).

_main.go_

```go
package main

import (
  "errors"
  "html/template"
  "io"

  "github.com/labstack/echo"

  "gitlab.com/ykyuen/golang-echo-template-example/handler"
)

// Define the template registry struct
type TemplateRegistry struct {
  templates map[string]*template.Template
}

// Implement e.Renderer interface
func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
  tmpl, ok := t.templates[name]
  if !ok {
    err := errors.New("Template not found -> " + name)
    return err
  }
  return tmpl.ExecuteTemplate(w, "base.html", data)
}

func main() {
  // Echo instance
  e := echo.New()

  // Instantiate a template registry with an array of template set
  // Ref: https://gist.github.com/rand99/808e6e9702c00ce64803d94abff65678
  templates := make(map[string]*template.Template)
  templates["home.html"] = template.Must(template.ParseFiles("view/home.html", "view/base.html"))
  templates["about.html"] = template.Must(template.ParseFiles("view/about.html", "view/base.html"))
  e.Renderer = &TemplateRegistry{
    templates: templates,
  }

  // Route => handler
  e.GET("/", handler.HomeHandler)
  e.GET("/about", handler.AboutHandler)

  // Start the Echo server
  e.Logger.Fatal(e.Start(":1323"))
}
```

We add a new route __/about__ which is handled by a **AboutHandler** and as you can see from the above highlighted lines, the **templates** map contains different set of template files for different HTML pages and the **Render()** takes the **name** parameter as the **templates** map key so it could execute the correct template set.

_view/base.html_

```html
{{define "base.html"}}
  <!DOCTYPE html>
  <html>
    <head>
      <title>{{template "title" .}}</title>
    </head>
    <body>
      {{template "body" .}}
    </body>
  </html>
{{end}}
```

The **template** statement tells the template engine that it should look for the `{{title}}` and `{{body}}` definitions in the template set and they are defined in the **home.html** and **about.html**.

_view/about.html_

```html
{{define "title"}}
  Boatswain Blog | {{index . "name"}}
{{end}}

{{define "body"}}
  <h1>{{index . "msg"}}</h1>
  <h2>This is the about page.</h2>
{{end}}
```

And here is the **AboutHanlder** which has no big difference from the **HomeHandler**.

_handler/about_handler.go_

```go
package handler

import (
  "net/http"

  "github.com/labstack/echo"
)

func AboutHandler(c echo.Context) error {
  // Please note the the second parameter "about.html" is the template name and should
  // be equal to one of the keys in the TemplateRegistry array defined in main.go
  return c.Render(http.StatusOK, "about.html", map[string]interface{}{
    "name": "About",
    "msg": "All about Boatswain!",
  })
}
```

## Summary

This is just a basic example implementing nested template using the [Go][golang] standard [html/template][html/template] library in [Echo][echo]. With proper setup, we could develop a more customized and convenient pattern for [Echo][echo] or even make it works with any other template engine.

The complete example could be found on [gitlab.com](https://gitlab.com/ykyuen/golang-echo-template-example).





[golang]: https://golang.org/
[echo]: https://echo.labstack.com/
[html/template]: https://godoc.org/html/template
[dep]: https://github.com/golang/dep