Skip to main content
Go Language Fundamentals for Beginners to Advanced
CHAPTER 25 Beginner

Web Development with Go

Updated: May 17, 2026
5 min read

# CHAPTER 25

Web Development with Go

1. Introduction

In Chapter 23, we built an API that returned raw JSON data to be consumed by front-end frameworks like React or Angular. However, sometimes you don't want a complex Javascript frontend. Sometimes you just want to return a fully rendered HTML webpage directly from the server. Go provides a brilliant standard package called html/template specifically for Server-Side Rendering (SSR).

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Serve static files (CSS, Images, Javascript).
  • Use html/template to render HTML files.
  • Inject dynamic Go variables into HTML.
  • Write basic Middleware to intercept HTTP requests.

3. Serving Static Files

To build a website, you need CSS and images. You must tell Go to publicly expose a folder containing these files.
go
123456789101112131415161718
package main

import (
    "fmt"
    "net/http"
)

func main() {
    // 1. Point to your local folder (e.g., ./static/)
    fs := http.FileServer(http.Dir("./static"))
    
    // 2. Map a URL route to that folder. 
    // StripPrefix removes the "/static/" from the URL before looking in the folder
    http.Handle("/static/", http.StripPrefix("/static/", fs))

    fmt.Println("Server running on port 8080...")
    http.ListenAndServe(":8080", nil)
}

*If you have a file ./static/style.css, a user can now view it at http://localhost:8080/static/style.css.*

4. HTML Templates

Writing HTML directly inside fmt.Fprintf(w, "<h1>Hello</h1>") is messy. Instead, we create a separate .html file and use Go's templating engine to inject data into it safely.

1. Create a file named index.html: We use double curly braces {{ . }} to indicate where Go should inject data.

html
12345678910
<!DOCTYPE html>
<html>
<head>
    <title>{{ .PageTitle }}</title>
</head>
<body>
    <h1>Welcome, {{ .UserName }}!</h1>
    <p>You have {{ .Messages }} new messages.</p>
</body>
</html>

2. Create the Go Handler (main.go):

go
123456789101112131415161718192021222324252627282930313233
package main

import (
    "html/template"
    "net/http"
)

// The Struct must have Exported (Capitalized) fields to be visible to the HTML!
type PageData struct {
    PageTitle string
    UserName  string
    Messages  int
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
    // 1. Parse the HTML file
    tmpl := template.Must(template.ParseFiles("index.html"))

    // 2. Prepare the data
    data := PageData{
        PageTitle: "Dashboard",
        UserName:  "Alice",
        Messages:  5,
    }

    // 3. Execute the template, passing the ResponseWriter and Data
    tmpl.Execute(w, data)
}

func main() {
    http.HandleFunc("/", homeHandler)
    http.ListenAndServe(":8080", nil)
}

5. Template Logic (Loops and If Statements)

Go's templating engine is powerful. You can write loops and conditionals directly inside the HTML file!
html
12345678910111213
<!-- If Statement -->
{{ if .IsAdmin }}
    <button>Delete User</button>
{{ else }}
    <p>Standard Access Only</p>
{{ end }}

<!-- For Loop over a Slice of strings named &#039;Fruits' -->
<ul>
{{ range .Fruits }}
    <li>{{ . }}</li>
{{ end }}
</ul>

6. Middleware Basics

Middleware is a function that intercepts an incoming HTTP request *before* it reaches your final handler. It is used for Logging, Authentication, or checking API Keys.

A basic Middleware takes an http.HandlerFunc, does some work, and then calls the original handler.

go
12345678910111213141516171819
func loggerMiddleware(next http.HandlerFunc) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // 1. Intercept and do work (e.g., Log the request URL)
        fmt.Println("Incoming Request received for:", r.URL.Path)

        // 2. Pass control to the final handler
        next.ServeHTTP(w, r)
    }
}

func securePage(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("This is the secure page."))
}

func main() {
    // Wrap the handler in the middleware!
    http.HandleFunc("/secure", loggerMiddleware(securePage))
    http.ListenAndServe(":8080", nil)
}

7. Common Mistakes

  • Unexported Template Data: If you pass a struct to tmpl.Execute, but the struct fields are lowercase (userName), the HTML file will render completely blank where the data should be. Templates are external to your package, so fields MUST be exported (Capitalized).
  • Cross-Site Scripting (XSS) Fears: You might worry that injecting user data into HTML is a security risk. Don't worry! Go's html/template package is Context-Aware. It automatically sanitizes and escapes malicious javascript injections natively.

8. Best Practices

  • Parse Templates Once: Parsing templates on every single HTTP request is slow. In production, you should use template.ParseGlob("templates/*.html") once at the very top of your main() function, and reuse that parsed variable in your handlers.

9. Exercises

  1. 1. Create a simple about.html file.
  1. 2. In Go, define a CompanyInfo struct containing the company name and year founded.
  1. 3. Serve the HTML page, passing the struct to display the data dynamically.

10. MCQs with Answers & Explanations

Question 1

Which package provides Context-Aware HTML rendering in Go?

Question 2

What syntax is used to inject Go variables inside an HTML template file?

Question 3

If you pass a struct to an HTML template, but the fields are lowercase, what happens?

Question 4

Which function allows you to serve static assets like CSS files and Images?

Q5. Can you write logic like if statements and for loops inside Go HTML templates? a) Yes, using {{ if }} and {{ range }} b) No, templates are strictly data-only Answer: a) Yes.
Question 6

What is the primary purpose of HTTP Middleware?

Q7. Is html/template safe from Cross-Site Scripting (XSS) injection attacks? a) Yes, it auto-escapes inputs based on whether it is placed in an HTML body, attribute, or JS script tag b) No, you must use a third-party library Answer: a) Yes, it is heavily Context-Aware and secure by default.

Q8. Should you call template.ParseFiles() inside the Handler function for high-traffic websites? a) Yes, so it always gets the latest file b) No, parsing files is disk I/O heavy. Parse them once at startup and cache them. Answer: b) No, parse them once at startup.

Question 9

Which function actually executes the parsed template and sends the HTML to the browser?

Question 10

What does {{ range .Users }} do in an HTML template?

11. Interview Preparation

Interview Questions:
  1. 1. Why is html/template preferred over text/template for web development in Go? (Answer: Context-aware auto-escaping for security).
  1. 2. What is Middleware? Describe a scenario where you would implement it in a Go REST API.
  1. 3. Why must struct fields be capitalized to be used in HTML templates?

12. Summary

Go is fully equipped to build both JSON APIs and traditional, server-rendered websites. The html/template package provides a highly secure, fast way to build dynamic pages. By combining templating with Middleware, you can build full-stack web applications without relying on external frameworks.

13. Next Chapter Recommendation

With our application logic complete, how do we know it actually works without manually clicking every button? In Chapter 26: Testing in Go, we will learn how to write Unit Tests to automatically verify that our code is flawless before deploying to production.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·