-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresponse.go
158 lines (127 loc) · 5.5 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package bowtie
import (
"encoding/json"
"net/http"
)
type ResponseWriterFactory func(w http.ResponseWriter) ResponseWriter
// Interface ResponseWriter extends the functionality provided by `http.ResponseWriter`, mainly
// by adding a few convenience methods for writing strings and JSON data and dealing with errors.
//
// You can provide your own extended ResponseWriter by creating a custom ResponseWriterFactory
// function and setting it to the ResponseWriterFactory property of your server.
type ResponseWriter interface {
http.ResponseWriter
// Add error safely adds a new error to the context, converting it to bowtie.Error if appropriate
AddError(err error)
// Errors returns an array that contains any error assigned to the response writer
Errors() []Error
// Status returns the HTTP status code of the writer. You can set this by using `WriteHeader()`
Status() int
// Written returns true if any data (including a status code) has been written to the writer's
// output stream
Written() bool
// WriteOrError checks if `err` is not nil, in which case it adds it to the context's error
// list and returns. If `err` is nil, `p` is written to the output stream instead. This is a
// convenient way of dealing with functions that return (data, error) tuples inside a middleware
WriteOrError(p []byte, err error) (int, error)
// WriteString is a convenience method that outputs a string
WriteString(s string) (int, error)
// WriteStringOrError is a convenience method that outputs a string or adds an error to the writer.
// It works like `WriteOrError`, but takes string instead of a byte array
WriteStringOrError(s string, err error) (int, error)
// WriteJSON writes data in JSON format to the output stream. The output Content-Type header
// is also automatically set to `application/json`
WriteJSON(data interface{}) (int, error)
// WriteJSONOrError checks if `err` is not nil, in which case it adds it to the context's error
// list and returns. If `err` is nil, `data` is serialized to JSON and written to the output
// stream instead; the Content-Type of the response is also set to `application/json` automatically.
// This is a convenient way of dealing with functions that return (data, error) tuples inside
// a middleware
WriteJSONOrError(data interface{}, err error) (int, error)
}
type ResponseWriterInstance struct {
http.ResponseWriter
written bool
errors []Error
status int
}
var _ ResponseWriter = &ResponseWriterInstance{}
func NewResponseWriter(w http.ResponseWriter) ResponseWriter {
return &ResponseWriterInstance{
ResponseWriter: w,
errors: []Error{},
status: 200,
}
}
// Errors returns an array that contains any error assigned to the response writer
func (r *ResponseWriterInstance) Errors() []Error {
return r.errors
}
// Add error safely adds a new error to the context, converting it to bowtie.Error if appropriate
func (r *ResponseWriterInstance) AddError(err error) {
if e, ok := err.(Error); ok {
r.WriteHeader(e.StatusCode())
} else {
r.WriteHeader(500)
}
r.errors = append(r.errors, NewErrorWithError(err))
}
// Status returns the HTTP status code of the writer. You can set this by using `WriteHeader()`
func (r *ResponseWriterInstance) Status() int {
return r.status
}
// WriteHeader writes a status header
func (r *ResponseWriterInstance) WriteHeader(status int) {
r.ResponseWriter.WriteHeader(status)
r.status = status
r.written = true
}
// Written returns true if any data (including a status code) has been written to the writer's
// output stream
func (r *ResponseWriterInstance) Written() bool {
return r.written
}
// Write implements io.Writer and outputs data to the HTTP stream
func (r *ResponseWriterInstance) Write(p []byte) (int, error) {
n, err := r.ResponseWriter.Write(p)
if err != nil {
r.written = true
}
return n, err
}
// WriteOrError checks if `err` is not nil, in which case it adds it to the context's error
// list and returns. If `err` is nil, `p` is written to the output stream instead. This is a
// convenient way of dealing with functions that return (data, error) tuples inside a middleware
func (r *ResponseWriterInstance) WriteOrError(p []byte, err error) (int, error) {
if err != nil {
r.AddError(err)
return 0, err
}
return r.Write(p)
}
// WriteString is a convenience method that outputs a string
func (r *ResponseWriterInstance) WriteString(s string) (int, error) {
return r.Write([]byte(s))
}
// WriteStringOrError is a convenience method that outputs a string or adds an error to the writer.
// It works like `WriteOrError`, but takes string instead of a byte array
func (r *ResponseWriterInstance) WriteStringOrError(s string, err error) (int, error) {
return r.WriteOrError([]byte(s), err)
}
// WriteJSON writes data in JSON format to the output stream. The output Content-Type header
// is also automatically set to `application/json`
func (r *ResponseWriterInstance) WriteJSON(data interface{}) (int, error) {
return r.WriteOrError(json.Marshal(data))
}
// WriteJSONOrError checks if `err` is not nil, in which case it adds it to the context's error
// list and returns. If `err` is nil, `data` is serialized to JSON and written to the output
// stream instead; the Content-Type of the response is also set to `application/json` automatically.
// This is a convenient way of dealing with functions that return (data, error) tuples inside
// a middleware
func (r *ResponseWriterInstance) WriteJSONOrError(data interface{}, err error) (int, error) {
if err != nil {
r.AddError(err)
return 0, err
}
return r.WriteJSON(data)
}