ehtml

package module
v0.2.1 Latest Latest
Warning

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

Go to latest
Published: Apr 20, 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>{{ .Status.Int }} {{ .Status }}</h1>
    <p>
        {{ .Message }} while serving {{ .Request.URL.Path }}.
        Request ID: {{ .ReqID }}
    </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>{{ .Status.Int }} {{ .Status }}</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: {{ .ReqID }}
    </i></p>
</body>
</html>
{{- end -}}

{{- define "404" -}}
<!DOCTYPE html>
<html lang="en">
<head>
    {{ template "head" . }}
</head>
<body>
    <h1>{{ .Status.Int}} {{ .Status }}</h1>
    <p>
        {{ .Request.URL.Path }} could not be found.
    </p>
</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

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

Optionally, extend Data to add more context. As an alternative, you can also roll your own implementation of Provider.

type data struct {
    Data
    ReqID int
}

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

err := p.Render(w, &data{Data{req, http.StatusInternalServerError, "DB connection"}, 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>{{ .Status.Int }} {{ .Status }}</h1>
	<p>
		{{ .Message }} while serving {{ .Request.URL.Path }}.
		Request ID: {{ .ReqID }}
	</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>{{ .Status.Int }} {{ .Status }}</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: {{ .ReqID }}
	</i></p>
</body>
</html>
{{- end -}}

{{- define "404" -}}
<!DOCTYPE html>
<html lang="en">
<head>
	{{ template "head" . }}
</head>
<body>
	<h1>{{ .Status.Int}} {{ .Status }}</h1>
	<p>
		{{ .Request.URL.Path }} could not be found.
	</p>
</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`

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

Optionally, extend `Data` to add more context. As an alternative, you can also roll your own implementation of `Provider`.

type data struct {
	Data
	ReqID int
}

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

err := p.Render(w, &data{Data{req, http.StatusInternalServerError, "DB connection"}, 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()

// Extend Data, as needed
type data struct {
	Data
	ReqID int
}

// Serves the client with the "500" template
err := p.Render(w, &data{Data{req, http.StatusInternalServerError, "DB connection"}, 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, &data{Data{req, http.StatusBadRequest, "Missing token in URL"}, 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))}

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

Index

Examples

Constants

View Source
const DefaultTmpl = `` /* 224-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 {
	Req  *http.Request
	Code Status
	Msg  string
}

Data can be used as a default or embedded type to implement Provider.

func (*Data) Message

func (d *Data) Message() string

Message implements Provider

func (*Data) Request

func (d *Data) Request() *http.Request

Request implements Provider

func (*Data) Status added in v0.2.0

func (d *Data) Status() Status

Status implements Provider

func (*Data) String

func (d *Data) String() string

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, dp Provider) error

Render a page for passed status code. In case of template execution errors, "RenderError" including the original status and message is sent to the client.

type Provider added in v0.2.0

type Provider interface {
	// Request returns the incomming http Request object
	Request() *http.Request
	Status() Status
	Message() string
	// String returns the status code, status text and message in a single string.
	// For example: "400 Bad Request: Parsing form data"
	String() string
}

Provider of data to templates

type Status added in v0.2.0

type Status int

Status holds an HTTP status code

func (Status) Int added in v0.2.0

func (s Status) Int() int

Int returns Status as int

func (Status) String added in v0.2.0

func (s Status) String() string

String returns the text descriptiom for the HTTP status code. It returns the empty string if the code is unknown.

Jump to

Keyboard shortcuts

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