Skip to content

Commit accf209

Browse files
feat: Simpler custom code error handling
1 parent 4f127ba commit accf209

File tree

4 files changed

+30
-14
lines changed

4 files changed

+30
-14
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ Update your existing handler signatures, by adding an `error` return type and ut
2222
func addProduct(w http.ResponseWriter, r *http.Request) error {
2323
var p product
2424
if err := errhandler.ParseJSON(r, &p); err != nil {
25-
return SendError(w, http.StatusUnprocessableEntity, err)
25+
return err
26+
27+
// Or, if you'd prefer to customise the status code:
28+
// errhandler.Error(http.StatusUnprocessableEntity, err)
2629
}
2730

2831
products[p.ID] = p

err.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package errhandler
2+
3+
// HTTPError allows you to return custom status codes.
4+
type HTTPError struct {
5+
status int
6+
err error
7+
}
8+
9+
// Error returns a new instance of Error.
10+
func Error(status int, err error) HTTPError {
11+
return HTTPError{
12+
status: status,
13+
err: err,
14+
}
15+
}
16+
17+
func (err HTTPError) Error() string {
18+
return err.err.Error()
19+
}

errhandler.go

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ type Wrap func(w http.ResponseWriter, r *http.Request) error
1313
// any errors encountered in the ErrHandlerFunc.
1414
func (fn Wrap) ServeHTTP(w http.ResponseWriter, r *http.Request) {
1515
if err := fn(w, r); err != nil {
16-
http.Error(w, err.Error(), http.StatusInternalServerError)
16+
if cerr, ok := err.(HTTPError); ok {
17+
http.Error(w, cerr.Error(), cerr.status)
18+
} else {
19+
http.Error(w, err.Error(), http.StatusInternalServerError)
20+
}
1721
}
1822
}
1923

@@ -37,16 +41,6 @@ func SendString(w http.ResponseWriter, message string) error {
3741
return nil
3842
}
3943

40-
// SendError returns an error response to the caller, or fails with an error.
41-
func SendError(w http.ResponseWriter, code int, err error) error {
42-
w.Header().Set("Content-Type", "text/plain")
43-
w.WriteHeader(code)
44-
if _, err := w.Write([]byte(err.Error())); err != nil {
45-
return err
46-
}
47-
return nil
48-
}
49-
5044
// ParseJSON can be used to parse a string from the body of a request.
5145
func ParseJSON(r *http.Request, val any) error {
5246
return json.NewDecoder(r.Body).Decode(val)

errhandler_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ func TestWrap_ServeHTTP(t *testing.T) {
6060
{
6161
name: "send error",
6262
handler: Wrap(func(w http.ResponseWriter, r *http.Request) error {
63-
return SendError(w, http.StatusUnprocessableEntity, fmt.Errorf("error doing stuff: %w", errors.New("database error")))
63+
return Error(http.StatusUnprocessableEntity, fmt.Errorf("error doing stuff: %w", errors.New("database error")))
6464
}),
6565
expectedStatus: http.StatusUnprocessableEntity,
66-
expectedBody: "error doing stuff: database error",
66+
expectedBody: "error doing stuff: database error\n",
6767
},
6868
{
6969
name: "error",

0 commit comments

Comments
 (0)