fix: make API type marshal before writing to respone writer to avoid duplicate write header calls on failed encoding

this fix is necessary to avoid the superflour write header error. When the
write fails, we log it, this shoudl never happen unless the connection gets
corrupted. In that case there is nothing for the server to do except log
pull/17759/head^2
Johnny Steenbergen 2020-04-15 12:43:20 -07:00 committed by Johnny Steenbergen
parent 0ec94e93a0
commit e295d508ac
2 changed files with 26 additions and 15 deletions

View File

@ -165,20 +165,35 @@ func (a *API) Respond(w http.ResponseWriter, status int, v interface{}) {
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
enc := json.NewEncoder(writer)
// this marshal block is to catch failures before they hit the http writer.
// default behavior for http.ResponseWriter is when body is written and no
// status is set, it writes a 200. Or if a status is set before encoding
// and an error occurs, there is no means to write a proper status code
// (i.e. 500) when that is to occur. This brings that step out before
// and then writes the data and sets the status code after marshaling
// succeeds.
var (
b []byte
err error
)
if a == nil || a.prettyJSON {
enc.SetIndent("", "\t")
b, err = json.MarshalIndent(v, "", "\t")
} else {
b, err = json.Marshal(v)
}
if err != nil {
a.Err(w, err)
return
}
w.WriteHeader(status)
if err := enc.Encode(v); err != nil {
a.Err(w, err)
return
if _, err := writer.Write(b); err != nil {
a.logErr("failed to write to response writer", zap.Error(err))
}
if err := writer.Close(); err != nil {
a.Err(w, err)
return
a.logErr("failed to close response writer", zap.Error(err))
}
}

View File

@ -98,8 +98,7 @@ func TestUserResourceMappingService_GetMembersHandler(t *testing.T) {
"status": "active"
}
]
}
`,
}`,
},
},
@ -162,8 +161,7 @@ func TestUserResourceMappingService_GetMembersHandler(t *testing.T) {
"status": "active"
}
]
}
`,
}`,
},
},
}
@ -273,8 +271,7 @@ func TestUserResourceMappingService_PostMembersHandler(t *testing.T) {
"id": "0000000000000001",
"name": "user0000000000000001",
"status": "active"
}
`,
}`,
},
},
@ -312,8 +309,7 @@ func TestUserResourceMappingService_PostMembersHandler(t *testing.T) {
"id": "0000000000000002",
"name": "user0000000000000002",
"status": "active"
}
`,
}`,
},
},
}