# Render [](http://godoc.org/github.com/unrolled/render) [](https://github.com/unrolled/render/actions)
Render is a package that provides functionality for easily rendering JSON, XML, text, binary data, and HTML templates.
## Usage
Render can be used with pretty much any web framework providing you can access the `http.ResponseWriter` from your handler. The rendering functions simply wraps Go's existing functionality for marshaling and rendering data.
- HTML: Uses the [html/template](http://golang.org/pkg/html/template/) package to render HTML templates.
- JSON: Uses the [encoding/json](http://golang.org/pkg/encoding/json/) package to marshal data into a JSON-encoded response.
- XML: Uses the [encoding/xml](http://golang.org/pkg/encoding/xml/) package to marshal data into an XML-encoded response.
- Binary data: Passes the incoming data straight through to the `http.ResponseWriter`.
- Text: Passes the incoming string straight through to the `http.ResponseWriter`.
~~~ go
// main.go
package main
import (
"encoding/xml"
"net/http"
"github.com/unrolled/render"
)
type ExampleXml struct {
XMLName xml.Name `xml:"example"`
One string `xml:"one,attr"`
Two string `xml:"two,attr"`
}
func main() {
r := render.New()
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("Welcome, visit sub pages now."))
})
mux.HandleFunc("/data", func(w http.ResponseWriter, req *http.Request) {
r.Data(w, http.StatusOK, []byte("Some binary data here."))
})
mux.HandleFunc("/text", func(w http.ResponseWriter, req *http.Request) {
r.Text(w, http.StatusOK, "Plain text here")
})
mux.HandleFunc("/json", func(w http.ResponseWriter, req *http.Request) {
r.JSON(w, http.StatusOK, map[string]string{"hello": "json"})
})
mux.HandleFunc("/jsonp", func(w http.ResponseWriter, req *http.Request) {
r.JSONP(w, http.StatusOK, "callbackName", map[string]string{"hello": "jsonp"})
})
mux.HandleFunc("/xml", func(w http.ResponseWriter, req *http.Request) {
r.XML(w, http.StatusOK, ExampleXml{One: "hello", Two: "xml"})
})
mux.HandleFunc("/html", func(w http.ResponseWriter, req *http.Request) {
// Assumes you have a template in ./templates called "example.tmpl"
// $ mkdir -p templates && echo "
Hello {{.}}.
" > templates/example.tmpl
r.HTML(w, http.StatusOK, "example", "World")
})
http.ListenAndServe("127.0.0.1:3000", mux)
}
~~~
~~~ html
Hello {{.}}.
~~~
### Available Options
Render comes with a variety of configuration options _(Note: these are not the default option values. See the defaults below.)_:
~~~ go
// ...
r := render.New(render.Options{
Directory: "templates", // Specify what path to load the templates from.
FileSystem: &LocalFileSystem{}, // Specify filesystem from where files are loaded.
Asset: func(name string) ([]byte, error) { // Load from an Asset function instead of file.
return []byte("template content"), nil
},
AssetNames: func() []string { // Return a list of asset names for the Asset function
return []string{"filename.tmpl"}
},
Layout: "layout", // Specify a layout template. Layouts can call {{ yield }} to render the current template or {{ partial "css" }} to render a partial from the current template.
Extensions: []string{".tmpl", ".html"}, // Specify extensions to load for templates.
Funcs: []template.FuncMap{AppHelpers}, // Specify helper function maps for templates to access.
Delims: render.Delims{"{[{", "}]}"}, // Sets delimiters to the specified strings.
Charset: "UTF-8", // Sets encoding for content-types. Default is "UTF-8".
DisableCharset: true, // Prevents the charset from being appended to the content type header.
IndentJSON: true, // Output human readable JSON.
IndentXML: true, // Output human readable XML.
PrefixJSON: []byte(")]}',\n"), // Prefixes JSON responses with the given bytes.
PrefixXML: []byte(""), // Prefixes XML responses with the given bytes.
HTMLContentType: "application/xhtml+xml", // Output XHTML content type instead of default "text/html".
IsDevelopment: true, // Render will now recompile the templates on every HTML response.
UseMutexLock: true, // Overrides the default no lock implementation and uses the standard `sync.RWMutex` lock.
UnEscapeHTML: true, // Ensure '&<>' are output correctly (JSON only).
StreamingJSON: true, // Streams the JSON response via json.Encoder.
HTMLTemplateOption: "missingkey=error", // Sets the option value for HTML templates. See https://pkg.go.dev/html/template#Template.Option for a list of known options.
RequirePartials: true, // Return an error if a template is missing a partial used in a layout.
DisableHTTPErrorRendering: true, // Disables automatic rendering of http.StatusInternalServerError when an error occurs.
JSONEncoder: func(w io.Writer) render.JSONEncoder { // Use jsoniter "github.com/json-iterator"
return jsoniter.NewEncoder(w)
},
})
// ...
~~~
### Default Options
These are the preset options for Render:
~~~ go
r := render.New()
// Is the same as the default configuration options:
r := render.New(render.Options{
Directory: "templates",
FileSystem: &LocalFileSystem{},
Asset: nil,
AssetNames: nil,
Layout: "",
Extensions: []string{".tmpl"},
Funcs: []template.FuncMap{},
Delims: render.Delims{"{{", "}}"},
Charset: "UTF-8",
DisableCharset: false,
IndentJSON: false,
IndentXML: false,
PrefixJSON: []byte(""),
PrefixXML: []byte(""),
BinaryContentType: "application/octet-stream",
HTMLContentType: "text/html",
JSONContentType: "application/json",
JSONPContentType: "application/javascript",
TextContentType: "text/plain",
XMLContentType: "application/xhtml+xml",
IsDevelopment: false,
UseMutexLock: false,
UnEscapeHTML: false,
HTMLTemplateOption: "",
StreamingJSON: false,
RequirePartials: false,
DisableHTTPErrorRendering: false,
RenderPartialsWithoutPrefix: false,
BufferPool: GenericBufferPool,
JSONEncoder: nil,
})
~~~
### JSON vs Streaming JSON
By default, Render does **not** stream JSON to the `http.ResponseWriter`. It instead marshalls your object into a byte array, and if no errors occurred, writes that byte array to the `http.ResponseWriter`. If you would like to use the built it in streaming functionality (`json.Encoder`), you can set the `StreamingJSON` setting to `true`. This will stream the output directly to the `http.ResponseWriter`. Also note that streaming is only implemented in `render.JSON` and not `render.JSONP`.
### Loading Templates
By default Render will attempt to load templates with a '.tmpl' extension from the "templates" directory. Templates are found by traversing the templates directory and are named by path and basename. For instance, the following directory structure:
~~~
templates/
|
|__ admin/
| |
| |__ index.tmpl
| |
| |__ edit.tmpl
|
|__ home.tmpl
~~~
Will provide the following templates:
~~~
admin/index
admin/edit
home
~~~
Templates can be loaded from an `embed.FS`.
~~~ go
// ...
//go:embed templates/*.html templates/*.tmpl
var embeddedTemplates embed.FS
// ...
r := render.New(render.Options{
Directory: "templates",
FileSystem: &render.EmbedFileSystem{
FS: embeddedTemplates,
},
Extensions: []string{".html", ".tmpl"},
})
// ...
~~~
You can also load templates from memory by providing the `Asset` and `AssetNames` options,
e.g. when generating an asset file using [go-bindata](https://github.com/jteeuwen/go-bindata).
### Layouts
Render provides `yield` and `partial` functions for layouts to access:
~~~ go
// ...
r := render.New(render.Options{
Layout: "layout",
})
// ...
~~~
~~~ html
My Layout
{{ partial "css" }}
{{ partial "header" }}
{{ yield }}
{{ partial "footer" }}
~~~
`current` can also be called to get the current template being rendered.
~~~ html
My Layout
This is the {{ current }} page.
~~~
Partials are defined by individual templates as seen below. The partial template's
name needs to be defined as "{partial name}-{template name}".
~~~ html
{{ define "header-home" }}
Home
{{ end }}
{{ define "footer-home"}}
The End
{{ end }}
~~~
By default, the template is not required to define all partials referenced in the
layout. If you want an error to be returned when a template does not define a
partial, set `Options.RequirePartials = true`.
### Character Encodings
Render will automatically set the proper Content-Type header based on which function you call. See below for an example of what the default settings would output (note that UTF-8 is the default, and binary data does not output the charset):
~~~ go
// main.go
package main
import (
"encoding/xml"
"net/http"
"github.com/unrolled/render"
)
type ExampleXml struct {
XMLName xml.Name `xml:"example"`
One string `xml:"one,attr"`
Two string `xml:"two,attr"`
}
func main() {
r := render.New(render.Options{})
mux := http.NewServeMux()
// This will set the Content-Type header to "application/octet-stream".
// Note that this does not receive a charset value.
mux.HandleFunc("/data", func(w http.ResponseWriter, req *http.Request) {
r.Data(w, http.StatusOK, []byte("Some binary data here."))
})
// This will set the Content-Type header to "application/json; charset=UTF-8".
mux.HandleFunc("/json", func(w http.ResponseWriter, req *http.Request) {
r.JSON(w, http.StatusOK, map[string]string{"hello": "json"})
})
// This will set the Content-Type header to "text/xml; charset=UTF-8".
mux.HandleFunc("/xml", func(w http.ResponseWriter, req *http.Request) {
r.XML(w, http.StatusOK, ExampleXml{One: "hello", Two: "xml"})
})
// This will set the Content-Type header to "text/plain; charset=UTF-8".
mux.HandleFunc("/text", func(w http.ResponseWriter, req *http.Request) {
r.Text(w, http.StatusOK, "Plain text here")
})
// This will set the Content-Type header to "text/html; charset=UTF-8".
mux.HandleFunc("/html", func(w http.ResponseWriter, req *http.Request) {
// Assumes you have a template in ./templates called "example.tmpl"
// $ mkdir -p templates && echo "
Hello {{.}}.
" > templates/example.tmpl
r.HTML(w, http.StatusOK, "example", "World")
})
http.ListenAndServe("127.0.0.1:3000", mux)
}
~~~
In order to change the charset, you can set the `Charset` within the `render.Options` to your encoding value:
~~~ go
// main.go
package main
import (
"encoding/xml"
"net/http"
"github.com/unrolled/render"
)
type ExampleXml struct {
XMLName xml.Name `xml:"example"`
One string `xml:"one,attr"`
Two string `xml:"two,attr"`
}
func main() {
r := render.New(render.Options{
Charset: "ISO-8859-1",
})
mux := http.NewServeMux()
// This will set the Content-Type header to "application/octet-stream".
// Note that this does not receive a charset value.
mux.HandleFunc("/data", func(w http.ResponseWriter, req *http.Request) {
r.Data(w, http.StatusOK, []byte("Some binary data here."))
})
// This will set the Content-Type header to "application/json; charset=ISO-8859-1".
mux.HandleFunc("/json", func(w http.ResponseWriter, req *http.Request) {
r.JSON(w, http.StatusOK, map[string]string{"hello": "json"})
})
// This will set the Content-Type header to "text/xml; charset=ISO-8859-1".
mux.HandleFunc("/xml", func(w http.