-
Notifications
You must be signed in to change notification settings - Fork 7
/
response.go
118 lines (92 loc) · 3.35 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
package httputil
import (
"context"
"encoding/json"
"encoding/xml"
"net/http"
"github.com/nexmoinc/gosrvlib/pkg/logging"
"go.uber.org/zap"
)
const (
// MimeApplicationJSON contains the mime type string for JSON content.
MimeApplicationJSON = "application/json; charset=utf-8"
// MimeApplicationXML contains the mime type string for XML content.
MimeApplicationXML = "application/xml; charset=utf-8"
// MimeTextPlain contains the mime type string for text content.
MimeTextPlain = "text/plain; charset=utf-8"
)
// JSend status codes.
const (
StatusSuccess = "success"
StatusFail = "fail"
StatusError = "error"
)
const (
logKeyResponseDataText = "response_txt"
logKeyResponseDataObject = "response_data"
)
// Status translates the HTTP status code to a JSend status string.
type Status int
// MarshalJSON implements the custom marshaling function for the json encoder.
func (sc Status) MarshalJSON() ([]byte, error) {
s := StatusSuccess
if sc >= http.StatusBadRequest { // 400+
s = StatusFail
}
if sc >= http.StatusInternalServerError { // 500+
s = StatusError
}
return json.Marshal(s) // nolint:wrapcheck
}
// SendStatus sends write a HTTP status code to the response.
func SendStatus(ctx context.Context, w http.ResponseWriter, statusCode int) {
defer logResponse(ctx, statusCode, logKeyResponseDataText, "")
http.Error(w, http.StatusText(statusCode), statusCode)
}
// SendJSON sends a JSON object to the response.
func SendJSON(ctx context.Context, w http.ResponseWriter, statusCode int, data interface{}) {
defer logResponse(ctx, statusCode, logKeyResponseDataObject, data)
writeHeaders(w, statusCode, MimeApplicationJSON)
if err := json.NewEncoder(w).Encode(data); err != nil {
logging.FromContext(ctx).Error("httputil.SendJSON()", zap.Error(err))
}
}
// SendXML sends an XML object to the response.
func SendXML(ctx context.Context, w http.ResponseWriter, statusCode int, data interface{}) {
defer logResponse(ctx, statusCode, logKeyResponseDataObject, data)
writeHeaders(w, statusCode, MimeApplicationXML)
if err := xml.NewEncoder(w).Encode(data); err != nil {
logging.FromContext(ctx).Error("httputil.SendXML()", zap.Error(err))
}
}
// SendText sends a JSON marshaled object to the response.
func SendText(ctx context.Context, w http.ResponseWriter, statusCode int, data string) {
defer logResponse(ctx, statusCode, logKeyResponseDataText, data)
writeHeaders(w, statusCode, MimeTextPlain)
if _, err := w.Write([]byte(data)); err != nil {
logging.FromContext(ctx).Error("httputil.SendText()", zap.Error(err))
}
}
// writeHeaders sets the content type with disabled caching.
func writeHeaders(w http.ResponseWriter, statusCode int, contentType string) {
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
w.Header().Set("Pragma", "no-cache")
w.Header().Set("Expires", "0")
w.Header().Set("Content-Type", contentType)
w.WriteHeader(statusCode)
}
// logResponse logs the response.
func logResponse(ctx context.Context, statusCode int, dataKey string, data interface{}) {
l := logging.FromContext(ctx)
reqLog := l.With(
zap.Int("response_code", statusCode),
zap.String("response_message", http.StatusText(statusCode)),
zap.Any("response_status", Status(statusCode)),
zap.Any(dataKey, data),
)
if statusCode >= http.StatusBadRequest { // 400+
reqLog.Error("Request")
} else {
reqLog.Debug("Request")
}
}