Basics

Responses

Content-negotiated HTML and JSON from the same handler.

HAMR's pkg/respond package gives you helpers that detect what the client wants — HTML for browsers and HTMX, JSON for API clients — and serve the right format. The same handler can do both.

HTML responses

respond.HTML
import "github.com/FyrmForge/hamr/pkg/respond"

func (h *handler) Show(c echo.Context) error {
    book, err := h.repo.Get(c.Request().Context(), c.Param("id"))
    if err != nil {
        return respond.Error(c, err)
    }
    return respond.HTML(c, http.StatusOK, showPage(c, book))
}

respond.HTML takes an Echo context, a status code, and a Templ component. It writes the right Content-Type header and renders the component to the response body.

JSON responses

respond.JSON
func (h *handler) ApiShow(c echo.Context) error {
    book, err := h.repo.Get(c.Request().Context(), c.Param("id"))
    if err != nil {
        return respond.Error(c, err)
    }
    return respond.JSON(c, http.StatusOK, book)
}

Error responses

respond.Error handles content negotiation for errors automatically. Browser clients get an HTML error page; HTMX clients get a fragment; API clients get a JSON error object.

respond.Error
if err != nil {
    return respond.Error(c, err)
}

// For specific status codes:
return respond.Error(c, echo.NewHTTPError(http.StatusNotFound, "book not found"))

Validation errors

respond.ValidationError renders form errors in a way both HTMX and JSON clients understand. For HTMX, it returns a 422 with field errors as out-of-band swaps. For JSON, it returns an error object with field-keyed messages.

respond.ValidationError
if err := form.Validate(input); err != nil {
    return respond.ValidationError(c, err, formPage(c, input))
}

Redirects

Use respond.Redirect for HTMX-aware redirects. For HTMX requests it sets HX-Redirect; for normal requests it returns a 303 with a Location header.

respond.Redirect
func (h *handler) Logout(c echo.Context) error {
    h.sessions.Destroy(c)
    return respond.Redirect(c, "/login")
}
Why not just c.Redirect?
Echo's c.Redirect doesn't know about HTMX. respond.Redirect sets the right header so HTMX swaps to the new page instead of trying to render the redirect target inline.