forked from pnelson/httpc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
render.go
101 lines (91 loc) · 2.44 KB
/
render.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package httpc
import (
"encoding/json"
"fmt"
"mime"
"net/http"
"strings"
"github.com/pnelson/tmpl"
)
// Viewable represents a view. To provide an expressive API, this
// type is an alias for interface{} that is named for documentation.
type Viewable interface{}
// Render writes the view in the requested format, if available.
func (ctx *Context) Render(view Viewable, code int) error {
accept := ctx.Request.Header.Get("Accept")
if accept == "" {
return ctx.RenderJSON(view, code)
}
for _, h := range strings.Split(accept, ",") {
media, _, err := mime.ParseMediaType(h)
if err != nil {
return err
}
switch media {
case "text/html", "text/*":
if renderer == nil {
continue
}
v, ok := view.(tmpl.Viewable)
if ok {
return ctx.RenderHTML(v, code)
}
case "application/json", "application/*", "*/*":
return ctx.RenderJSON(view, code)
case "text/plain":
return ctx.RenderPlain(view, code)
}
}
return ctx.Abort(http.StatusNotAcceptable)
}
// Renderer represents the ability to render a tmpl.Viewable.
type Renderer interface {
Render(view tmpl.Viewable) ([]byte, error)
}
// renderer is used to render HTML templates.
var renderer Renderer
// SetRenderer sets the Renderer used to render HTML templates.
// This function is not thread safe and is intended to be called
// once during application initialization.
func SetRenderer(r Renderer) {
mu.Lock()
renderer = r
mu.Unlock()
}
// RenderHTML writes the view as templated HTML.
func (ctx *Context) RenderHTML(view tmpl.Viewable, code int) error {
b, err := renderer.Render(view)
if err != nil {
return err
}
ctx.Header().Set("Content-Type", "text/html; charset=utf-8")
ctx.WriteHeader(code)
_, err = ctx.Write(b)
return err
}
// RenderJSON writes the view as marshalled JSON.
func (ctx *Context) RenderJSON(view Viewable, code int) error {
b, err := json.Marshal(view)
if err != nil {
return err
}
ctx.Header().Set("Content-Type", "application/json; charset=utf-8")
ctx.WriteHeader(code)
if view == nil {
return nil
}
_, err = ctx.Write(b)
return err
}
// RenderPlain writes the view as a string.
func (ctx *Context) RenderPlain(view Viewable, code int) error {
s, ok := view.(string)
if !ok {
return fmt.Errorf("httpc: view for RenderPlain must be a string")
}
ctx.Header().Set("Content-Type", "text/plain; charset=utf-8")
ctx.Header().Set("X-Content-Type-Options", "nosniff")
ctx.WriteHeader(code)
_, err := fmt.Fprintln(ctx, s)
return err
}