lewisdale.dev/src/blog/posts/2024/5/learning-go-day-13.md
Lewis Dale d410995778
All checks were successful
Build and copy to prod / build-and-copy (push) Successful in 2m12s
Learning go: day 13
2024-05-14 13:03:13 +01:00

2.7 KiB

title date tags excerpt
Learning Go: Day Thirteen 2024-05-15T08:00:00.0Z
learning
go
Creating some basic HTML output, and bundling static files

So now I want to start working on putting together a basic interface. This post won't be about creating the interface itself, but instead just the ground work that will allow me to build it over the next post or two.

Creating some HTML output

Alright, this was actually really straightforward. There's a module called html/template that can be used to parse HTML, and includes a templating language.

So I've created a super-simple HTML template at templates/index.html, and then use the template.ParseFiles function to parse and display it:

<!-- templates/index.html -->

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Oopsie</title>
    </head>
    <body>
        <h1>Oopsie uptime monitoring</h1>
    </body>
</html>
// main.go

http.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
    pings := ping.ListGroupedBySite(db)

    if _, err := json.Marshal(pings); err != nil {
        w.Write([]byte(err.Error()))
        w.WriteHeader(http.StatusInternalServerError)
        return
    } else {
        w.Header().Set("Content-Type", "text/html")

        t, _ := template.ParseFiles("templates/index.html")
        t.Execute(w, nil)
    }
})

This works! But I can't deploy it, because when I compile the binary and upload it to my server it can't find the template files. Luckily, there's a package that can help me do that.

Bundling static files

This part is basically magic. I have no idea how it works, but there is a package called embed. I can use it to create an instance of FS with some bundled static content, and that then gets bundled into my binary, and it takes about 3 lines of code to do it 🤯.

// main.go

import (
    "embed"
)

//go:embed templates/*
var content embed.FS

http.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
    pings := ping.ListGroupedBySite(db)

    if _, err := json.Marshal(pings); err != nil {
        w.Write([]byte(err.Error()))
        w.WriteHeader(http.StatusInternalServerError)
        return
    } else {
        w.Header().Set("Content-Type", "text/html")

        t, _ := template.ParseFS(content, "templates/index.html")
        t.Execute(w, nil)
    }
})

And then when I run go build, the resulting binary file has the HTML bundled in it and I can run it on my server. This is a really powerful thing to have built directly into the standard library.

So that's it for today, like I mentioned earlier, my next one or two posts will mostly be focused on making a UI.