On this page

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

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.