tsweb: refactor JSONHandler to take status code from error if it is present (#905)
This change is to make JSONHandler error handling intuitive, as before there would be two sources of HTTP status code when HTTPErrors were generated: one as the first return value of the handler function, and one nested inside the HTTPError. Previously, it took the first return value as the status code, and ignored the code inside the HTTPError. Now, it should expect the first return value to be 0 if there is an error, and it takes the status code of the HTTPError to set as the response code. Signed-off-by: Daniel Chung <daniel@tailscale.com>
This commit is contained in:
@ -19,7 +19,7 @@ type response struct {
|
||||
// JSONHandlerFunc is an HTTP ReturnHandler that writes JSON responses to the client.
|
||||
//
|
||||
// Return a HTTPError to show an error message, otherwise JSONHandlerFunc will
|
||||
// only report "internal server error" to the user.
|
||||
// only report "internal server error" to the user with status code 500.
|
||||
type JSONHandlerFunc func(r *http.Request) (status int, data interface{}, err error)
|
||||
|
||||
// ServeHTTPReturn implements the ReturnHandler interface.
|
||||
@ -31,23 +31,12 @@ type JSONHandlerFunc func(r *http.Request) (status int, data interface{}, err er
|
||||
// return http.StatusBadRequest, nil, err
|
||||
// }
|
||||
//
|
||||
// See jsonhandler_text.go for examples.
|
||||
// See jsonhandler_test.go for examples.
|
||||
func (fn JSONHandlerFunc) ServeHTTPReturn(w http.ResponseWriter, r *http.Request) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var resp *response
|
||||
status, data, err := fn(r)
|
||||
if status == 0 {
|
||||
status = http.StatusInternalServerError
|
||||
resp = &response{
|
||||
Status: "error",
|
||||
Error: "internal server error",
|
||||
}
|
||||
} else if err == nil {
|
||||
resp = &response{
|
||||
Status: "success",
|
||||
Data: data,
|
||||
}
|
||||
} else {
|
||||
if err != nil {
|
||||
if werr, ok := err.(HTTPError); ok {
|
||||
resp = &response{
|
||||
Status: "error",
|
||||
@ -61,12 +50,29 @@ func (fn JSONHandlerFunc) ServeHTTPReturn(w http.ResponseWriter, r *http.Request
|
||||
if werr.Msg != "" {
|
||||
err = fmt.Errorf("%s: %w", werr.Msg, err)
|
||||
}
|
||||
// take status from the HTTPError to encourage error handling in one location
|
||||
if status != 0 && status != werr.Code {
|
||||
err = fmt.Errorf("[unexpected] non-zero status that does not match HTTPError status, status: %d, HTTPError.code: %d: %w", status, werr.Code, err)
|
||||
}
|
||||
status = werr.Code
|
||||
} else {
|
||||
status = http.StatusInternalServerError
|
||||
resp = &response{
|
||||
Status: "error",
|
||||
Error: "internal server error",
|
||||
}
|
||||
}
|
||||
} else if status == 0 {
|
||||
status = http.StatusInternalServerError
|
||||
resp = &response{
|
||||
Status: "error",
|
||||
Error: "internal server error",
|
||||
}
|
||||
} else if err == nil {
|
||||
resp = &response{
|
||||
Status: "success",
|
||||
Data: data,
|
||||
}
|
||||
}
|
||||
|
||||
b, jerr := json.Marshal(resp)
|
||||
|
Reference in New Issue
Block a user