Wrapper for clean handlers in Go
package web | |
import ( | |
"bytes" | |
"encoding/json" | |
"io" | |
"net/http" | |
) | |
type errorResponse struct { | |
Error string `json:"error"` | |
} | |
type Action func(r *http.Request) *Response | |
type Headers map[string]string | |
type Response struct { | |
Status int | |
ContentType string | |
Content io.Reader | |
Headers Headers | |
} | |
func Error(status int, err error, headers Headers) *Response { | |
return &Response{ | |
Status: status, | |
Content: bytes.NewBufferString(err.Error()), | |
Headers: headers, | |
} | |
} | |
func ErrorJSON(status int, err error, headers Headers) *Response { | |
errResp := errorResponse{ | |
Error: err.Error(), | |
} | |
b, err := json.Marshal(errResp) | |
if err != nil { | |
return Error(http.StatusInternalServerError, err, headers) | |
} | |
return &Response{ | |
Status: status, | |
ContentType: "application/json", | |
Content: bytes.NewBuffer(b), | |
Headers: headers, | |
} | |
} | |
func Data(status int, content []byte, headers Headers) *Response { | |
return &Response{ | |
Status: status, | |
Content: bytes.NewBuffer(content), | |
Headers: headers, | |
} | |
} | |
func DataJSON(status int, v interface{}, headers Headers) *Response { | |
b, err := json.Marshal(v) | |
if err != nil { | |
return ErrorJSON(http.StatusInternalServerError, err, headers) | |
} | |
return &Response{ | |
Status: status, | |
ContentType: "application/json", | |
Content: bytes.NewBuffer(b), | |
Headers: headers, | |
} | |
} | |
func DataWithReader(status int, r io.Reader, headers Headers) *Response { | |
return &Response{ | |
Status: status, | |
Content: r, | |
Headers: headers, | |
} | |
} | |
func (a Action) ServeHTTP(rw http.ResponseWriter, r *http.Request) { | |
if response := a(r); response != nil { | |
if response.ContentType != "" { | |
rw.Header().Set("Content-Type", response.ContentType) | |
} | |
for k, v := range response.Headers { | |
rw.Header().Set(k, v) | |
} | |
rw.WriteHeader(response.Status) | |
_, err := io.Copy(rw, response.Content) | |
if err != nil { | |
rw.WriteHeader(http.StatusInternalServerError) | |
} | |
} else { | |
rw.WriteHeader(http.StatusOK) | |
} | |
} |
This comment has been minimized.
This comment has been minimized.
https://elithrar.github.io/article/custom-handlers-avoiding-globals/ showcase the problem this pattern solves. |
This comment has been minimized.
This comment has been minimized.
@nowylie Because this way you can keep the handlers clear and clean, without the use of early return in. I explain it in more detail here: https://blog.bartfokker.nl/ |
This comment has been minimized.
This comment has been minimized.
@imas thank you for sharing this link |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
At first I really liked your approach, but after some thought I'm not sure that you're really gaining much value. Why not just write some utility functions? gist