Skip to content

Instantly share code, notes, and snippets.

@giautm
Created February 14, 2023 22:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save giautm/1a206ae80536b4b0da7bfb91487478a8 to your computer and use it in GitHub Desktop.
Save giautm/1a206ae80536b4b0da7bfb91487478a8 to your computer and use it in GitHub Desktop.
package handler
type (
options struct {
MaxPayload int64
}
// HandlerOptions is a function that configures the handler.
HandlerOptions func(*options)
)
// WithMaxPayload sets the maximum payload size for the handler.
func WithMaxPayload(max int64) HandlerOptions {
return func(o *options) {
o.MaxPayload = max
}
}
// MakeHandler returns an http.HandlerFunc that decodes the request body into
// the provided type, calls the provided handler, and encodes the result as JSON.
func MakeHandler[R any, S any](handle func(context.Context, R) (S, error), opts ...HandlerOptions) http.HandlerFunc {
opt := &options{MaxPayload: 0}
for _, o := range opts {
o(opt)
}
return func(w http.ResponseWriter, r *http.Request) {
if m := opt.MaxPayload; m > 0 && r.ContentLength > m {
log.Printf("Payload too large: %d, limited to %d", r.ContentLength, m)
http.Error(w, "Payload too large", http.StatusRequestEntityTooLarge)
return
}
var p R
if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
log.Printf("json.NewDecoder: %v", err)
http.Error(w, "Error parsing request", http.StatusBadRequest)
return
}
result, err := handle(r.Context(), p)
if err != nil {
http.Error(w, "Error processing request", http.StatusInternalServerError)
return
}
w.Header().Add("Content-Type", "application/json")
if err = json.NewEncoder(w).Encode(result); err != nil {
log.Printf("json.NewEncoder: %v", err)
http.Error(w, `{"error":"internal server error"}`, http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment