Response Helpers
MuxMaster provides a small set of functions that write complete HTTP responses in one call. They set the appropriate Content-Type header, call WriteHeader, and write the body.
Functions
JSON
func JSON(w http.ResponseWriter, code int, v any) error
Marshals v to JSON, sets Content-Type: application/json; charset=utf-8, writes the status code, and writes the body.
// Object
muxmaster.JSON(w, http.StatusOK, user)
// Slice
muxmaster.JSON(w, http.StatusOK, users)
// Inline map
muxmaster.JSON(w, http.StatusCreated, map[string]any{
"id": 42,
"name": "Alice",
})
// Error response
muxmaster.JSON(w, http.StatusNotFound, map[string]string{
"error": "user not found",
})
Passing 0 as the code defaults to 200 OK.
Returns the marshalling or write error; it does not write anything if marshalling fails.
XML
func XML(w http.ResponseWriter, code int, v any) error
Marshals v to XML, sets Content-Type: application/xml; charset=utf-8, and writes the response.
type User struct {
XMLName xml.Name `xml:"user"`
ID int `xml:"id,attr"`
Name string `xml:"name"`
}
muxmaster.XML(w, http.StatusOK, User{ID: 42, Name: "Alice"})
Text
func Text(w http.ResponseWriter, code int, s string) error
Writes s as plain text with Content-Type: text/plain; charset=utf-8.
muxmaster.Text(w, http.StatusOK, "pong")
muxmaster.Text(w, http.StatusOK, fmt.Sprintf("hello, %s", name))
Redirect
func Redirect(w http.ResponseWriter, r *http.Request, code int, url string)
Issues an HTTP redirect. Delegates to http.Redirect.
muxmaster.Redirect(w, r, http.StatusMovedPermanently, "/new-path")
muxmaster.Redirect(w, r, http.StatusFound, "https://example.com")
NoContent
func NoContent(w http.ResponseWriter)
Writes a 204 No Content response with no body.
mux.DELETE("/users/:id", func(w http.ResponseWriter, r *http.Request) {
db.DeleteUser(muxmaster.PathParam(r, "id"))
muxmaster.NoContent(w)
})
Using Helpers with HandlerFuncE
The helpers return errors, which makes them natural to use in error-returning handlers:
mux.GETE("/users/:id", func(w http.ResponseWriter, r *http.Request) error {
id, err := muxmaster.ParamsFromContext(r.Context()).Int("id")
if err != nil {
return muxmaster.Error(http.StatusBadRequest, err)
}
user, err := db.FindUser(id)
if err != nil {
return muxmaster.Error(http.StatusNotFound, errors.New("not found"))
}
return muxmaster.JSON(w, http.StatusOK, user)
})
If JSON fails (e.g. the value cannot be marshalled), the error is returned to the ErrorHandler.
Using Standard encoding/json Directly
For streaming or large responses where you want more control, use encoding/json directly:
mux.GET("/users", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK)
if err := json.NewEncoder(w).Encode(users); err != nil {
log.Printf("encode error: %v", err)
}
})
The helpers are a convenience for the common case; they do not restrict your options.
See Also
- Error Handling —
HandlerFuncEandErrorHandler - Getting Started — JSON responses in context
Upstream source
The JSON, Text, XML, Stream, and conditional-GET helpers covered above are implemented in response.go in the upstream repository.
Common questions
How do I write a JSON response from a handler?
Call mux.JSON(w, status, value). The helper sets Content-Type: application/json; charset=utf-8, encodes the value with encoding/json, writes the status, and returns any error from the encoder so callers can decide whether to log or surface it.
How do I serve a conditional GET (304)?
Set the ETag (or Last-Modified) header before writing the body and call mux.IfNoneMatch(w, r, etag) (or IfModifiedSince). The helper returns true and writes the 304 short-circuit when the request's conditional headers match; the handler returns immediately without writing the body.
How do I stream a response without buffering it in memory?
Use mux.Stream(w, contentType, reader). The helper sets the content type, copies the reader to the response writer with a fixed-size buffer, and flushes between chunks where the underlying writer supports it. The reader is closed after the copy completes.