perf: use json.Encode to avoid extra allocation (#5596)

When sending JSON back to the client — and we do a lot of that, use
the streaming implementation of json.Encode rather than marshalling
the data into an intermediate byte array.

One curious detail here is that the streaming implementation
uses newlines to mark the end of the stream, so a few unit tests had
to be updated to expect this. Previously we would only emit a trailing
newline if "pretty" was configured.

Signed-off-by: Anders Eknert <anders@styra.com>
This commit is contained in:
Anders Eknert
2023-01-26 09:49:19 +01:00
committed by GitHub
parent 070a3f2b2b
commit d001ac49d2
3 changed files with 9 additions and 18 deletions
+1 -1
View File
@@ -3431,7 +3431,7 @@ func TestUnversionedPost(t *testing.T) {
f.reset()
f.server.Handler.ServeHTTP(f.recorder, post())
expected := `{"agg":6}`
expected := "{\"agg\":6}\n"
if f.recorder.Code != 200 || f.recorder.Body.String() != expected {
t.Fatalf(`Expected HTTP 200 / %v but got: %v`, expected, f.recorder)
}
+6 -15
View File
@@ -58,27 +58,18 @@ func Error(w http.ResponseWriter, status int, err *types.ErrorV1) {
// JSON writes a response with the specified status code and object. The object
// will be JSON serialized.
func JSON(w http.ResponseWriter, code int, v interface{}, pretty bool) {
var bs []byte
var err error
enc := json.NewEncoder(w)
if pretty {
bs, err = json.MarshalIndent(v, "", " ")
} else {
bs, err = json.Marshal(v)
enc.SetIndent("", " ")
}
if err != nil {
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(code)
if err := enc.Encode(v); err != nil {
ErrorAuto(w, err)
return
}
headers := w.Header()
headers.Add("Content-Type", "application/json")
Bytes(w, code, bs)
if pretty {
_, _ = w.Write([]byte("\n"))
}
}
// Bytes writes a response with the specified status code and bytes.