Let's Go Guided exercises › Add an 'About' page to the application
Previous · Contents · Next
Chapter 16.1.

Add an ‘About’ page to the application

Your goal for this exercise is to add a new ‘About’ page to the application. It should be mapped to the GET /about route, available to both authenticated and unauthenticated users, and look similar to this:

16.01-01.png

Step 1

Create a GET /about route which maps to a new about handler. Think about which middleware stack is appropriate for the route to use.

Show suggested code

Step 2

Create a new ui/html/pages/about.tmpl file, following the same template pattern that we’ve used for the other pages of the application. Include a title, heading and some placeholder copy for the ‘About’ page.

Show suggested code

Step 3

Update the main navigation bar for the application to include a link to the new ‘About’ page (the link should be visible to all users, irrespective of whether they are logged in or not).

Show suggested code

Step 4

Update the about handler so that it renders the about.tmpl file that you’ve just created. Then sanity check that the new page and navigation works by visiting https://localhost:4000/about in your browser.

Show suggested code

Suggested code

Suggested code for step 1

File: cmd/web/handlers.go
package main

...

func (app *application) about(w http.ResponseWriter, r *http.Request) {
    // Some code will go here later...
}
File: cmd/web/routes.go
package main

...

func (app *application) routes() http.Handler {
    mux := http.NewServeMux()

    mux.Handle("GET /static/", http.FileServerFS(ui.Files))

    mux.HandleFunc("GET /ping", ping)

    dynamic := alice.New(app.sessionManager.LoadAndSave, noSurf, app.authenticate)

    mux.Handle("GET /{$}", dynamic.ThenFunc(app.home))
    // Add the about route.
    mux.Handle("GET /about", dynamic.ThenFunc(app.about))
    mux.Handle("GET /snippet/view/{id}", dynamic.ThenFunc(app.snippetView))
    mux.Handle("GET /user/signup", dynamic.ThenFunc(app.userSignup))
    mux.Handle("POST /user/signup", dynamic.ThenFunc(app.userSignupPost))
    mux.Handle("GET /user/login", dynamic.ThenFunc(app.userLogin))
    mux.Handle("POST /user/login", dynamic.ThenFunc(app.userLoginPost))

    protected := dynamic.Append(app.requireAuthentication)

    mux.Handle("GET /snippet/create", protected.ThenFunc(app.snippetCreate))
    mux.Handle("POST /snippet/create", protected.ThenFunc(app.snippetCreatePost))
    mux.Handle("POST /user/logout", protected.ThenFunc(app.userLogoutPost))

    standard := alice.New(app.recoverPanic, app.logRequest, commonHeaders)
    return standard.Then(mux)
}

Suggested code for step 2

File: ui/html/pages/about.tmpl
{{define "title"}}About{{end}}

{{define "main"}}
    <h2>About</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi at mauris dignissim,
    consectetur tellus in, fringilla ante. Pellentesque habitant morbi tristique senectus
    et netus et malesuada fames ac turpis egestas. Sed dignissim hendrerit scelerisque.</p>
    <p>Praesent a dignissim arcu. Cras a metus sagittis, pellentesque odio sit amet,
    lacinia velit. In hac habitasse platea dictumst. </p>
{{end}}

Suggested code for step 3

File: ui/html/partials/nav.tmpl
{{define "nav"}}
<nav>
    <div>
        <a href='/'>Home</a>
        <!-- Include a new link, visible to all users -->
        <a href='/about'>About</a>
         {{if .IsAuthenticated}}
            <a href='/snippet/create'>Create snippet</a>
        {{end}}
    </div>
    <div>
        {{if .IsAuthenticated}}
            <form action='/user/logout' method='POST'>
                <input type='hidden' name='csrf_token' value='{{.CSRFToken}}'>
                <button>Logout</button>
            </form>
        {{else}}
            <a href='/user/signup'>Signup</a>
            <a href='/user/login'>Login</a>
        {{end}}
    </div>
</nav>
{{end}}

Suggested code for step 4

File: cmd/web/handlers.go
package main

...

func (app *application) about(w http.ResponseWriter, r *http.Request) {
    data := app.newTemplateData(r)
    app.render(w, r, http.StatusOK, "about.tmpl", data)
}