-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathencoder.go
More file actions
88 lines (78 loc) · 2.2 KB
/
encoder.go
File metadata and controls
88 lines (78 loc) · 2.2 KB
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
package mux
import (
"encoding/json"
"errors"
"io"
"mime"
"net/http"
"strings"
)
// Viewable represents a view. To provide an expressive API, this
// type is an alias for interface{} that is named for documentation.
type Viewable interface{}
// Encoder represents the ability to encode HTTP responses.
type Encoder interface {
Encode(w io.Writer, view Viewable) error
Headers() http.Header
}
// EncoderFunc represents the ability to negotiate an Encoder
// from an incoming HTTP request. Return the error ErrEncodeMatch
// to respond with a 406 Not Acceptable error.
type EncoderFunc func(req *http.Request) (Encoder, error)
// ErrEncodeMatch indicates that request failed to negotiate an Encoder.
var ErrEncodeMatch = errors.New("mux: no encoder matched request")
// Encode encodes the view and responds to the request.
func (h *Handler) Encode(w http.ResponseWriter, req *http.Request, view Viewable, code int) error {
e, err := h.encoder(req)
if err != nil {
return err
}
b := h.pool.Get()
defer h.pool.Put(b)
err = e.Encode(b, view)
if err != nil {
return err
}
headers := w.Header()
for k, vs := range e.Headers() {
for _, v := range vs {
headers.Add(k, v)
}
}
w.WriteHeader(code)
_, err = b.WriteTo(w)
return err
}
// NewAcceptEncoder returns an EncoderFunc that returns the
// first Encoder negotiated from the request Accept header.
func NewAcceptEncoder(encoders map[string]Encoder) EncoderFunc {
fn := func(req *http.Request) (Encoder, error) {
accept := req.Header.Get("Accept")
// mime.ParseMediaType returns an unexported error for
// the empty string, so we short-circuit it here.
// An exact match is great, too.
e, ok := encoders[accept]
if ok {
return e, nil
}
for _, t := range strings.Split(accept, ",") {
mediaType, _, err := mime.ParseMediaType(t)
if err != nil {
return nil, err
}
e, ok := encoders[mediaType]
if ok {
return e, nil
}
}
return nil, ErrEncodeMatch
}
return fn
}
type jsonEncoder struct{}
func (*jsonEncoder) Encode(w io.Writer, view Viewable) error {
return json.NewEncoder(w).Encode(view)
}
func (*jsonEncoder) Headers() http.Header {
return http.Header{"Content-Type": []string{"application/json; charset=utf-8"}}
}