Macaron Documentation
  • Welcome
  • Starter Guide
  • Core Concepts
  • Core Services
  • Custom Services
  • Middlewares
    • Routing
    • Templating
    • Gzip
    • Localization
    • Data Binding and Validation
    • Cache
    • Captcha
    • Session
    • Cross-Site Request Forgery
    • Embed Binary Data
    • Serving Multiple Sites
  • FAQs
  • 简体中文
    • 初学者指南
    • 核心概念
    • 核心服务
    • 自定义服务
    • 中间件和辅助模块
      • 路由模块
      • 模板引擎
      • Gzip 压缩
      • 应用本地化
      • 数据绑定与验证
      • 缓存管理(Cache)
      • 验证码服务
      • 会话管理(Session)
      • 跨域请求攻击(CSRF)
      • 嵌入二进制数据
      • 服务多个站点
    • 常见问题
Powered by GitBook
On this page
  • Render HTML
  • Go Templating Engine
  • Pongo2 Templating Engine
  • Template Sets
  • Quick summary on rendering HTML
  • Render XML, JSON and raw content
  • Response status, error and redirect
  • Change template path at runtime
  • Example

Was this helpful?

  1. Middlewares

Templating

PreviousRoutingNextGzip

Last updated 5 years ago

Was this helpful?

There are two official middlewares built for templating for your Macaron application currently, which are and .

You're free to choose one of them to use, and one Macaron only uses one templating engine.

Common behaviors:

  • Both of them are supporting render XML, JSON and raw content as response, the only difference between them is the way to render HTML.

  • Both of them use templates as default template file directory.

  • Both of them use .tmpl and .html as default template file extensions.

  • Both of them use to determine whether to cache template files(when macaron.Env == macaron.PROD) or not.

Render HTML

Go Templating Engine

This service can be injected by function and is represented by type . It is optional to use, normally, you should use *macaron.Context.Render.This service uses Go built-in templating engine to render your HTML. If you want to know about details of how it works, please see .

Example

Suppose you have following directory structure:

main/
    |__ main.go
    |__ templates/
            |__ hello.tmpl

hello.tmpl:

<h1>Hello {{.Name}}</h1>

main.go:

package main

import "gopkg.in/macaron.v1"

func main() {
    m := macaron.Classic()
    m.Use(macaron.Renderer())

    m.Get("/", func(ctx *macaron.Context) {
        ctx.Data["Name"] = "jeremy"
        ctx.HTML(200, "hello") // 200 is the response code.
    })

    m.Run()
}

Options

package main

import "gopkg.in/macaron.v1"

func main() {
    m := macaron.Classic()
    m.Use(macaron.Renderer(macaron.RenderOptions{
        // Directory to load templates. Default is "templates".
        Directory: "templates",
        // Extensions to parse template files from. Defaults are [".tmpl", ".html"].
        Extensions: []string{".tmpl", ".html"},
        // Funcs is a slice of FuncMaps to apply to the template upon compilation. Default is [].
        Funcs: []template.FuncMap{map[string]interface{}{
            "AppName": func() string {
                return "Macaron"
            },
            "AppVer": func() string {
                return "1.0.0"
            },
        }},
        // Delims sets the action delimiters to the specified strings. Defaults are ["{{", "}}"].
        Delims: macaron.Delims{"{{", "}}"},
        // Appends the given charset to the Content-Type header. Default is "UTF-8".
        Charset: "UTF-8",
        // Outputs human readable JSON. Default is false.
        IndentJSON: true,
        // Outputs human readable XML. Default is false.
        IndentXML: true,
        // Prefixes the JSON output with the given bytes. Default is no prefix.
        PrefixJSON: []byte("macaron"),
        // Prefixes the XML output with the given bytes. Default is no prefix.
        PrefixXML: []byte("macaron"),
        // Allows changing of output to XHTML instead of HTML. Default is "text/html".
        HTMLContentType: "text/html",
    }))        
    // ...
}

Pongo2 Templating Engine

Example

Suppose you have following directory structure:

main/
    |__ main.go
    |__ templates/
            |__ hello.tmpl

hello.tmpl:

<h1>Hello {{Name}}</h1>

main.go:

package main

import (
    "github.com/go-macaron/pongo2"
    "gopkg.in/macaron.v1"
)

func main() {
    m := macaron.Classic()
    m.Use(pongo2.Pongoer())

    m.Get("/", func(ctx *macaron.Context) {
        ctx.Data["Name"] = "jeremy"
        ctx.HTML(200, "hello") // 200 is the response code.
    })

    m.Run()
}

Options

package main

import (
    "github.com/go-macaron/pongo2"
    "gopkg.in/macaron.v1"
)

func main() {
    m := macaron.Classic()
    m.Use(pongo2.Pongoer(pongo2.Options{
        // Directory to load templates. Default is "templates".
        Directory: "templates",
        // Extensions to parse template files from. Defaults are [".tmpl", ".html"].
        Extensions: []string{".tmpl", ".html"},
        // Appends the given charset to the Content-Type header. Default is "UTF-8".
        Charset: "UTF-8",
        // Outputs human readable JSON. Default is false.
        IndentJSON: true,
        // Outputs human readable XML. Default is false.
        IndentXML: true,
        // Allows changing of output to XHTML instead of HTML. Default is "text/html".
        HTMLContentType: "text/html",
    }))        
    // ...
}

Template Sets

When you have more than one type of template files, you should use template sets, which allows you decide which one to render dynamically at runtime.

To use it in Go templating engine:

// ...
m.Use(macaron.Renderers(macaron.RenderOptions{
    Directory: "templates/default",
}, "theme1:templates/theme1", "theme2:templates/theme2"))

m.Get("/foobar", func(ctx *macaron.Context) {
    ctx.HTML(200, "hello")
})

m.Get("/foobar1", func(ctx *macaron.Context) {
    ctx.HTMLSet(200, "theme1", "hello")
})

m.Get("/foobar2", func(ctx *macaron.Context) {
    ctx.HTMLSet(200, "theme2", "hello")
})
// ...

To use it in Pongo2 templating engine:

// ...
m.Use(pongo2.Pongoers(pongo2.Options{
    Directory: "templates/default",
}, "theme1:templates/theme1", "theme2:templates/theme2"))

m.Get("/foobar", func(ctx *macaron.Context) {
    ctx.HTML(200, "hello")
})

m.Get("/foobar1", func(ctx *macaron.Context) {
    ctx.HTMLSet(200, "theme1", "hello")
})

m.Get("/foobar2", func(ctx *macaron.Context) {
    ctx.HTMLSet(200, "theme2", "hello")
})
// ...

The option argument is aiming for defualt template set and settings, and a list of name-directory pairs separate by :.

If the last part of template directory is same as your template set name, you can omit it as follows:

// ...
m.Use(macaron.Renderers(RenderOptions{
    Directory: "templates/default",
}, "templates/theme1", "templates/theme2"))

m.Get("/foobar", func(ctx *macaron.Context) {
    ctx.HTML(200, "hello")
})

m.Get("/foobar1", func(ctx *macaron.Context) {
    ctx.HTMLSet(200, "theme1", "hello")
})

m.Get("/foobar2", func(ctx *macaron.Context) {
    ctx.HTMLSet(200, "theme2", "hello")
})
// ...

Helper methods for template sets

To check if given template set exists:

// ...
m.Get("/foobar", func(ctx *macaron.Context) {
    ok := ctx.HasTemplateSet("theme2")
    // ...
})
// ...

To change template set directory:

// ...
m.Get("/foobar", func(ctx *macaron.Context) {
    ctx.SetTemplatePath("theme2", "templates/new/theme2")
    // ...
})
// ...

Quick summary on rendering HTML

As you can see, the only difference between two templating engines to render HTML is the syntax of template files, in the code level, they are exactly the same.

If you just want to get results of rendered HTML, call method *macaron.Context.Render.HTMLString:

package main

import "gopkg.in/macaron.v1"

func main() {
    m := macaron.Classic()
    m.Use(macaron.Renderer())

    m.Get("/", func(ctx *macaron.Context) {
        ctx.Data["Name"] = "jeremy"
        output, err := ctx.HTMLString("hello")
        // Do other operations
    })

    m.Run()
}

Render XML, JSON and raw content

It is fairly easy to render XML, JSON and raw content compare to HTML.

package main

import "gopkg.in/macaron.v1"

type Person struct {
    Name string
    Age  int
    Sex  string
}

func main() {
    m := macaron.Classic()
    m.Use(macaron.Renderer())

    m.Get("/xml", func(ctx *macaron.Context) {
        p := Person{"Unknwon", 21, "male"}
        ctx.XML(200, &p)
    })
    m.Get("/json", func(ctx *macaron.Context) {
        p := Person{"Unknwon", 21, "male"}
        ctx.JSON(200, &p)
    })
    m.Get("/raw", func(ctx *macaron.Context) {
        ctx.RawData(200, []byte("raw data goes here"))
    })
    m.Get("/text", func(ctx *macaron.Context) {
        ctx.PlainText(200, []byte("plain text goes here"))
    })

    m.Run()
}

Response status, error and redirect

To response status, error and redirect:

package main

import "gopkg.in/macaron.v1"

func main() {
    m := macaron.Classic()
    m.Use(macaron.Renderer())

    m.Get("/status", func(ctx *macaron.Context) {
        ctx.Status(403)
    })
    m.Get("/error", func(ctx *macaron.Context) {
        ctx.Error(500, "Internal Server Error")
    })
    m.Get("/redirect", func(ctx *macaron.Context) {
        ctx.Redirect("/") // The second argument is response code, default is 302.
    })

    m.Run()
}

Change template path at runtime

In case you want to change your template path at runtime, call method *macaron.Context.SetTemplatePath. Note that this operation applies to global, not just current request.

Example

Suppose you have following directory structure:

main/
    |__ main.go
    |__ templates/
            |__ hello.tmpl
    |__ templates2/
            |__ hello.tmpl

templates/hello.tmpl:

<h1>Hello {{.Name}}</h1>

templates2/hello.tmpl:

<h1>What's up, {{.Name}}</h1>

main.go:

package main

import "gopkg.in/macaron.v1"

func main() {
    m := macaron.Classic()
    m.Use(macaron.Renderer())

    m.Get("/old", func(ctx *macaron.Context) {
        ctx.Data["Name"] = "Unknwon"
        ctx.HTML(200, "hello")
        // Empty string refers to default template set.
        ctx.SetTemplatePath("", "templates2")
    })
    m.Get("/new", func(ctx *macaron.Context) {
        ctx.Data["Name"] = "Unknwon"
        ctx.HTML(200, "hello")
    })

    m.Run()
}

When you first request /old, the response will be <h1>Hello Unknwon</h1>, right after response, the template path has been changed to template2. So when you request /new, the response will be <h1>What's up, Unknwon</h1>.

This service also accepts one argument for custom options():

This service can be injected by function and is represented by type . It is optional to use, normally, you should use *macaron.Context.Render.This service uses Pongo2 v3 templating engine to render your HTML. If you want to know about details of how it works, please see .

This service also accepts one argument for custom options():

As you can see, the only difference here is two functions and .

macaron.RenderOptions
pongo2.Pongoer
macaron.Render
pongo2 documentation
pongo2.Options
macaron.Renderers
pongo2.Pongoers
macaron.Renderer
pongo2.Pongoer
Macaron Env
macaron.Renderer
macaron.Render
html/template documentation
Instance