Autostrada
Autostrada
Create a new codebase Get Autostrada Plus
Documentation Changelog Roadmap Give feedback
Login

DocumentationTraditional web application › Sending HTML responses

Sending HTML responses

Autostrada provides a variety of helper functions for sending both full HTML pages and arbitrary HTML snippets to clients.

By default, your HTML should live in standard library html/template templates inside the assets/templates directory. For guidance on how to use html/template, please see the official documentation.

If you open the assets/templates directory in your generated codebase, you'll see that it already contains a base.tmpl file and two subdirectories: pages and partials.

You can – and should – restructure these templates to suit you application's needs, but the default templates provide a good starting point.

Sending full web pages

The files in the pages directory 'extend' the base template with page-specific content.

By default, each file should define a page:title template containing the page title, and a page:main template containing the main body content for the page. You can also optionally define a page:meta template containing any additional meta tags or other content to include in the HTML <head> section.

For example, you could create a pages/random.tmpl file to display a random number with content like this:

{{define "page:title"}}Random number generator{{end}}

{{define "page:meta"}}
<meta name="description" content="This page displays a random integer">
{{end}}

{{define "page:main"}}
<p>Your random number is: {{.Number}}.</p>
{{end}}

To send this page to the client, you can use the response.Page() function defined in internal/response/templates.go. This function injects the page-specific content into the base.tmpl template and sends the complete HTML page to the client.

The function accepts the HTTP status code to use for the response, along with any data that you want to pass to the template.

For example, to send the pages/random.tmpl page along with a 200 OK status code:

func (app *application) exampleHandler(w http.ResponseWriter, r *http.Request) {
    data := app.newTemplateData(r)
    data["Number"] = rand.Int()

    err := response.Page(w, http.StatusOK, data, "pages/random.tmpl")
    if err != nil {
        app.serverError(w, r, err)
    }
}

In this example we're also using the app.newTemplateData() helper to construct the data for the template. This helper can be found in the cmd/web/helpers.go file, and it returns a map[string]any containing common data for use in HTML templates.

The contents of this map will vary depending on the options selected when generating your codebase, but it will include at least the application's app.config.baseURL configuration setting and version number. Feel free to extend app.newTemplateData() with any additional shared template data that your application needs.

If you want to include specific HTTP headers in the response, you can use the response.PageWithHeaders() function instead. For example:

func (app *application) exampleHandler(w http.ResponseWriter, r *http.Request) {
    data := app.newTemplateData(r)
    data["Number"] = rand.Int()

    headers := make(http.Header)
    headers.Set("X-Server", "Go")

    err := response.PageWithHeaders(w, http.StatusOK, data, headers, "pages/random.tmpl")
    if err != nil {
        app.serverError(w, r, err)
    }
}
Using partials

Sometimes you may have snippets of HTML that you want to reuse in multiple pages or places. When this happens, you can define a template containing the HTML in any file inside the partials directory.

For example, you could create a partials/images.tmpl file containing reusable image partials like this:

{{define "partial:images:logo"}}
<img src="/static/img/logo.jpg" alt="Company logo" loading="lazy">
{{end}}

{{define "partial:images:headshot"}}
<img src="/static/img/me.jpg" alt="Alice Smith" loading="lazy">
{{end}}

All templates defined inside the partials directory are automatically available to your base and page templates when using the response.Page() or response.PageWithHeaders() functions.

Continuing the random number example, if you wanted to insert the logo partial at the bottom of the page you could do so like this:

{{define "page:title"}}Random number generator{{end}}

{{define "page:main"}}
<p>Your random number is: {{.Number}}.</p>

{{template "partial:images:logo" .}}
{{end}}

Please note:

Sending HTML snippets

The internal/response package also provides a response.NamedTemplate() function that you can use to send the contents of a specific template to the client.

This is mainly useful if you want to send the client a partial HTML response, rather than a fully-formed HTML page – which is common when using front-end libraries like HTMX, Hotwire, or Unpoly.

The response.NamedTemplate() function requires you to pass the name of the template you you want to send, along with the path to the file where that named template can be found.

For example, if you want to send the partial:nav template from the partials/nav.tmpl file, along with a 200 OK status code, you would use it like this:

func (app *application) exampleHandler(w http.ResponseWriter, r *http.Request) {
	data := app.newTemplateData(r)

	err := response.NamedTemplate(w, http.StatusOK, data, "partial:nav", "partials/nav.tmpl")
	if err != nil {
		app.serverError(w, r, err)
	}
}

There is also a response.NamedTemplateWithHeaders() function that you can use if you want to send specific HTTP headers in the response. You can use it like so:

func (app *application) exampleHandler(w http.ResponseWriter, r *http.Request) {
	headers := make(http.Header)
	headers.Set("X-Server", "Go")

	data := app.newTemplateData(r)

	err := response.NamedTemplateWithHeaders(w, http.StatusOK, data, headers, "partial:nav", "partials/nav.tmpl")
	if err != nil {
		app.serverError(w, r, err)
	}
}

Note: All the files in the assets/templates directory are embedded into your application binary and can be accessed via the EmbeddedFiles variable in assets/efs.go.