Documentation › Traditional web application › 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/html directory. For guidance on how to use html/template, please see the official documentation.
If you open the assets/html directory in your generated codebase, you'll see that it already contains a base.tmpl file and two subdirectories: pages and components.
base.tmpl file contains the shared HTML markup for all your web pages. You can think of this as your 'layout' file.pages directory contain the specific HTML markup for individual web pages. You can see an example in pages/home.tmpl, which contains the markup for the homepage.components directory contain reusable HTML snippets that can be included in different pages or send as standalone snippets to the client. You can see an example in components/nav.tmpl, which contains the markup for the navigation bar.You can – and should – restructure these templates to suit you application's needs, but the default templates provide a good starting point.
The files in the pages directory contain the page-specific content that is 'injected' into the base.tmpl template.
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 app.html.RenderBase() method defined in internal/response/html.go. This function injects the page-specific content into the base 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.defaultHTMLData(r)
data["Number"] = rand.Int()
err := app.html.RenderBase(w, http.StatusOK, data, "pages/random.tmpl")
if err != nil {
app.serverError(w, r, err)
}
}
In this example we're also using the app.defaultHTMLData() 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.defaultHTMLData() 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 app.html.RenderBaseWithHeaders() function instead. For example:
func (app *application) exampleHandler(w http.ResponseWriter, r *http.Request) {
data := app.defaultHTMLData(r)
data["Number"] = rand.Int()
headers := make(http.Header)
headers.Set("X-Server", "Go")
err := app.html.RenderBaseWithHeaders(w, http.StatusOK, data, headers, "pages/random.tmpl")
if err != nil {
app.serverError(w, r, err)
}
}
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 components directory.
For example, you could create a components/images.tmpl file containing reusable image components like this:
{{define "component:image:logo"}}
<img src="/static/img/logo.jpg" alt="Company logo" loading="lazy">
{{end}}
{{define "component:images:headshot"}}
<img src="/static/img/me.jpg" alt="Alice Smith" loading="lazy">
{{end}}
All templates defined inside the components directory are automatically available to your base and page templates when using the app.html.RenderBase() function.
Continuing the random number example, if you wanted to insert the logo component 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 "component:image:logo" .}}
{{end}}
Please note:
components directory must have unique names, even if they are defined in different files..tmpl extension for the files under components.: characters in the template names don't have any special meaning. You could give them any names you want, so long as they are unique. Names like component-image-logo or component_image_logo would also be fine, although I recommended avoiding using the . character in template names, because it has a special meaning in Go templates and could be confusing to readers.The codebase also includes a app.html.Render() method 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 app.html.Render() method 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 contents of the components:nav template from the components/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.defaultHTMLData(r)
err := app.html.Render(w, http.StatusOK, data, "component:nav", "components/nav.tmpl")
if err != nil {
app.serverError(w, r, err)
}
}
There is also a response.RenderWithHeaders() 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.defaultHTMLData(r)
err := app.html.Render(w, http.StatusOK, data, headers, "component:nav", "components/nav.tmpl")
if err != nil {
app.serverError(w, r, err)
}
}
Note: All the files in the assets/html directory are embedded into your application binary and can be accessed via the HTMLFiles variable in assets/efs.go.