-
Notifications
You must be signed in to change notification settings - Fork 382
/
response.go
129 lines (112 loc) · 3.52 KB
/
response.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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package rest
import (
"bufio"
"encoding/json"
"net"
"net/http"
)
const xPoweredByDefault = "go-json-rest"
// A ResponseWriter interface dedicated to JSON HTTP response.
// Note that the object instantiated by the ResourceHandler that implements this interface,
// also happens to implement http.ResponseWriter, http.Flusher and http.CloseNotifier.
type ResponseWriter interface {
// Identical to the http.ResponseWriter interface
Header() http.Header
// Use EncodeJson to generate the payload, write the headers with http.StatusOK if they
// are not already written, then write the payload.
// The Content-Type header is set to "application/json", unless already specified.
WriteJson(v interface{}) error
// Encode the data structure to JSON, mainly used to wrap ResponseWriter in middlewares.
EncodeJson(v interface{}) ([]byte, error)
// Similar to the http.ResponseWriter interface, with additional JSON related headers set.
WriteHeader(int)
}
// Error produces an error response in JSON with the following structure, '{"Error":"My error message"}'
// The standard plain text net/http Error helper can still be called like this:
// http.Error(w, "error message", code)
func Error(w ResponseWriter, error string, code int) {
w.WriteHeader(code)
err := w.WriteJson(map[string]string{"Error": error})
if err != nil {
panic(err)
}
}
// NotFound produces a 404 response with the following JSON, '{"Error":"Resource not found"}'
// The standard plain text net/http NotFound helper can still be called like this:
// http.NotFound(w, r.Request)
func NotFound(w ResponseWriter, r *Request) {
Error(w, "Resource not found", http.StatusNotFound)
}
// Private responseWriter intantiated by the resource handler.
// It implements the following interfaces:
// ResponseWriter
// http.ResponseWriter
// http.Flusher
// http.CloseNotifier
// http.Hijacker
type responseWriter struct {
http.ResponseWriter
wroteHeader bool
isIndented bool
xPoweredBy string
}
func (w *responseWriter) WriteHeader(code int) {
if w.Header().Get("Content-Type") == "" {
w.Header().Set("Content-Type", "application/json")
}
if len(w.xPoweredBy) > 0 {
w.Header().Add("X-Powered-By", w.xPoweredBy)
}
w.ResponseWriter.WriteHeader(code)
w.wroteHeader = true
}
func (w *responseWriter) EncodeJson(v interface{}) ([]byte, error) {
var b []byte
var err error
if w.isIndented {
b, err = json.MarshalIndent(v, "", " ")
} else {
b, err = json.Marshal(v)
}
if err != nil {
return nil, err
}
return b, nil
}
// Encode the object in JSON and call Write.
func (w *responseWriter) WriteJson(v interface{}) error {
b, err := w.EncodeJson(v)
if err != nil {
return err
}
_, err = w.Write(b)
if err != nil {
return err
}
return nil
}
// Provided in order to implement the http.ResponseWriter interface.
func (w *responseWriter) Write(b []byte) (int, error) {
if !w.wroteHeader {
w.WriteHeader(http.StatusOK)
}
return w.ResponseWriter.Write(b)
}
// Provided in order to implement the http.Flusher interface.
func (w *responseWriter) Flush() {
if !w.wroteHeader {
w.WriteHeader(http.StatusOK)
}
flusher := w.ResponseWriter.(http.Flusher)
flusher.Flush()
}
// Provided in order to implement the http.CloseNotifier interface.
func (w *responseWriter) CloseNotify() <-chan bool {
notifier := w.ResponseWriter.(http.CloseNotifier)
return notifier.CloseNotify()
}
// Provided in order to implement the http.Hijacker interface.
func (w *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hijacker := w.ResponseWriter.(http.Hijacker)
return hijacker.Hijack()
}