Controllers

Formats And MIME

Negotiate HTML, JSON, Turbo, image, and custom responses from controller actions.

By Guillermo Alvarez - Published - Updated

Check the current format

Controllers can inspect negotiated formats:

if c.IsJSON() {
    return c.Render("show")
}

GoLazy reads Turbo headers, registered path suffixes such as .html, .json, or app-defined suffixes like .md, then the Accept header, and defaults to HTML. A path suffix is stripped before routing, so /posts/hello.md reaches the same route as /posts/hello.

Branch with Wants

Use Wants when one action serves multiple formats:

return c.Wants(lazycontroller.Formats{
    lazycontroller.HTML: func() error {
        c.Set("post", post)
        return nil
    },
    lazycontroller.JSON: func() error {
        c.Set("post", post)
        return c.Render("show")
    },
})

Wants returns 406 Not Acceptable when none of the declared formats match.

Register a custom format

Custom MIME types use NewFormat:

var Markdown = lazycontroller.NewFormat(
    "text/markdown",
    lazycontroller.As("markdown"),
    lazycontroller.Suffix("md", "markdown"),
)

Then branch on the custom format:

return c.Wants(lazycontroller.Formats{
    lazycontroller.HTML: func() error {
        return c.renderHTMLPost(post)
    },
    Markdown: func() error {
        c.ContentType("text/markdown; charset=utf-8")
        _, err := w.Write([]byte(post.Body))
        return err
    },
})

Render format templates

Render("show") selects a template for the current format:

show.html.tpl
show.json.tpl
show.turbo_stream.tpl

HTML renders through the selected layout. JSON and Turbo Stream responses render without a layout.

Use Turbo frame requests

Turbo frame requests use the Turbo-Frame header. If the request targets car, GoLazy can render:

_car_frame.html.tpl

and wrap it in:

<turbo-frame id="car">...</turbo-frame>

Use Hotwire Turbo for view helpers and frame examples.