ehtml

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 8, 2020 License: BSD-3-Clause Imports: 6 Imported by: 2

README

Build Status codecov Go Report Card GoDoc

eHTML

Package ehtml provides ways of rendering an error html page, using Go templates.

Too many time we've found ourselves writing customized error pages. With this package we hope to relieve ourselves from this trivial, but yet repetetive job.

Simply load your templates into the object and call Render() with the request, status code and optional data.

Writing a generic web server? Waiting for templates from your designer? No problem! A default placeholder template will be used instead.

Example

Define some templates:

{{- define "head" -}}
<head>
    <meta charset="utf-8">
    <title>{{ .String }}</title>
</head>
{{- end -}}

{{- define "error" -}}
<!DOCTYPE html>
<html lang="en">
{{ template "head" }}
<body>
    <h1>{{ .StatusCode }} {{ .StatusText }}</h1>
    <p>
        {{ .Message }} while serving {{ .Request.URL.Path }}.
        Request ID: {{ .Data.RequestID }}
    </p>
    <p><i>This is a generic error page</i><p>
</body>
</html>
{{- end -}}

{{- define "500" -}}
<!DOCTYPE html>
<html lang="en">
{{ template "head" }}
<body>
    <h1>Snap!</h1>
    <h2>{{ .StatusCode }} {{ .StatusText }}</h2>
    <p>
        Something went really wrong and we've been notified!
        Please try again later.
    </p>
    <p><i>
        Error: {{ .Message }} while serving {{ .Request.URL.Path }}.
        Request ID: {{ .Data.RequestID }}
    </i></p>
</body>
</html>
{{- end -}}

{{- define "404" -}}
<!DOCTYPE html>
<html lang="en">
<head>
    {{ template "head" }}
</head>
<body>
    <h1>{{ .StatusCode }} {{ .StatusText }}</h1>
    <p>
        {{ .Request.URL.Path }} could not be found.
</body>
</html>
{{- end -}}

Parse them into a globale variable (or part of your Handler object). One can also use ParseFiles() or ParseGlob():

var errorPages = &Pages{template.Must(template.New("error").Parse(templates))}

If you are using Gorilla mux, set the NotFoundHandler

r := mux.NewRouter()
r.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if err := p.Render(w, r, http.StatusNotFound, "", nil); err != nil {
        log.Println(err)
    }
})

And whenever something goes wrong in your handlers, call Render():

err := p.Render(w, req, http.StatusInternalServerError, "DB connection", struct{ RequestID int }{666})
if err != nil {
    log.Println(err)
}

License

BSD 3 Clause.

Documentation

Overview

Package ehtml provides ways of rendering an error html page, using Go templates. It supports status code specific templates, with fallback to a generic error template. If no templates are defined, it uses a simple placeholder template.

Define some templates:

{{- define "head" -}}
<head>
	<meta charset="utf-8">
	<title>{{ .String }}</title>
</head>
{{- end -}}

{{- define "error" -}}
<!DOCTYPE html>
<html lang="en">
{{ template "head" }}
<body>
	<h1>{{ .StatusCode }} {{ .StatusText }}</h1>
	<p>
		{{ .Message }} while serving {{ .Request.URL.Path }}.
		Request ID: {{ .Data.RequestID }}
	</p>
	<p><i>This is a generic error page</i><p>
</body>
</html>
{{- end -}}

{{- define "500" -}}
<!DOCTYPE html>
<html lang="en">
{{ template "head" }}
<body>
	<h1>Snap!</h1>
	<h2>{{ .StatusCode }} {{ .StatusText }}</h2>
	<p>
		Something went really wrong and we've been notified!
		Please try again later.
	</p>
	<p><i>
		Error: {{ .Message }} while serving {{ .Request.URL.Path }}.
		Request ID: {{ .Data.RequestID }}
	</i></p>
</body>
</html>
{{- end -}}

{{- define "404" -}}
<!DOCTYPE html>
<html lang="en">
<head>
	{{ template "head" }}
</head>
<body>
	<h1>{{ .StatusCode }} {{ .StatusText }}</h1>
	<p>
		{{ .Request.URL.Path }} could not be found.
</body>
</html>
{{- end -}}

Parse them into a globale variable (or part of your Handler object):

var errorPages = &Pages{template.Must(template.New("error").Parse(templates))}

If you are using Gorilla mux, set the `NotFoundHandler`

r := mux.NewRouter()
r.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	if err := p.Render(w, r, http.StatusNotFound, "", nil); err != nil {
		log.Println(err)
	}
})

And whenever something goes wrong in your handlers, call `Render()`:

err := p.Render(w, req, http.StatusInternalServerError, "DB connection", struct{ RequestID int }{666})
if err != nil {
	log.Println(err)
}
Example
p := &Pages{template.Must(template.New("error").Parse(exampleTemplates))}

req := httptest.NewRequest("GET", "http://example.com/foo", nil)
w := httptest.NewRecorder()

// Serves the client with the "500" template
err := p.Render(w, req, http.StatusInternalServerError, "DB connection", struct{ RequestID int }{666})
if err != nil {
	log.Println(err)
}

resp := w.Result()
body, _ := ioutil.ReadAll(resp.Body)

fmt.Println(resp.StatusCode)
fmt.Println(string(body))

w = httptest.NewRecorder()

// 400 is not defined, so the generic "error" template is used instead.
err = p.Render(w, req, http.StatusBadRequest, "Missing token in URL", struct{ RequestID int }{667})
if err != nil {
	log.Println(err)
}

resp = w.Result()
body, _ = ioutil.ReadAll(resp.Body)

fmt.Println(resp.StatusCode)
fmt.Println(string(body))
Example (NotFoundHandler)
p := &Pages{template.Must(template.New("error").Parse(exampleTemplates))}

r := mux.NewRouter()
r.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	if err := p.Render(w, r, http.StatusNotFound, "", nil); err != nil {
		log.Println(err)
	}
})

Index

Examples

Constants

View Source
const DefaultTmpl = `` /* 228-byte string literal not displayed */

DefaultTmpl is a placeholder template for `Pages.Render()`

View Source
const RenderError = "500 Internal server error. While handling:\n%s"

RenderError is returned to the client if the template failed to render. This doesn't look nice, but it prevents partial responses.

Variables

This section is empty.

Functions

This section is empty.

Types

type Data

type Data struct {
	Request    *http.Request // Request object as passed to `Render()`
	StatusCode int
	Message    string
	Data       interface{} // Optional, additional Data
}

Data available in templates.

func (*Data) StatusText

func (d *Data) StatusText() string

StatusText returns a text for the HTTP status code. It returns the empty string if the code is unknown.

func (*Data) String

func (d *Data) String() string

String returns the status code, status text and message in a single string. For example, in a template:

{{ .String }} => 400 Bad Request: Parsing form data

type Pages

type Pages struct {
	Tmpl *template.Template
}

Pages allows setting of status page templates. Whenever such page needs to be served, a Lookup is done for a template named by the code. Eg: "404". A generic template named "error" can be provided and will be used if there is no status-specific template defined.

If Tmpl is `nil` or no templates are found using above Lookup scheme, `DefaultErrTmpl` will be used.

func (*Pages) Render

func (p *Pages) Render(w http.ResponseWriter, r *http.Request, statusCode int, msg string, data interface{}) error

Render a page for passed status code. Data and Request are optional and can be nil, if the template doesn't need them. They are passed to the template as-is.

In case of template execution errors, RenderError including the original status and message is sent to the client.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL