---
title: "Learning Go: Day Seven"
date: 2024-05-07T08:00:00.0Z
tags:
    - learning
    - go
excerpt: "Kicking off the project by starting to build out an HTTP server"
---

So, yesterday I [decided I was going to build an uptime monitor and status page](/post/learning-go-day-six.md). To recap, here's the list of things I need to figure out how to do:

* Run a web server
* Render web pages with some dynamic content
* Store & read data from/to a database
* Send requets to a server & handle the responses
* Do all of the above on a periodic schedule

I've decided to call the project Oopsie, because that's what I'll say when things go red, and have setup the repo on [my git server](https://git.lewisdale.dev/lewis/oopsie). Like on [day one](https://lewisdale.dev/post/learning-go-day-one), I initialised my Go module:

```bash
go mod init lewisdale.dev/oopsie
```

And then created my `main.go` file.

## Creating a web server and handling my first request

Once again, Go's standard library comes to the rescue, as there are libraries for dealing with HTTP requests built right into the runtime. The [net/http package](https://pkg.go.dev/net/http) has functions for creating a server, listening for requests, and even serving static assets, which is really useful.

My first server, and request handler, is the ever-original "Hello, world":

```go
package main

import (
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello, World!"))
	})
	http.ListenAndServe(":8000", nil)
}
```

It's fairly straightforward. The `http.HandleFunc` call registers a handler on the root URL, and `http.ResponseWriter.Write` outputs a string, which is converted to a slice of bytes. Then I start the actual server on port 8000 with `http.ListenAndServe`. Truly, riveting stuff.


## Pattern-matching handlers

The pattern syntax for `HandleFunc` is something called ServeMux, which I don't fully understand but fortunately the syntax is well-documented on the [package docs](https://pkg.go.dev/net/http#hdr-Patterns). It's not too dissimilar to most other URL pattern-matching libraries[^1]. Generally the syntax is:

1. `/` - match the root 
2. `/something` - explictly match a URL
3. `/something-else/` - matching any URL where the path starts with `/something-else/`
4. `/route/{param}` - match a URL that starts with `/route/` and then has an arbitrary parameter in the second block of the path

You can also prefix the paths with either the request method, host name, or both. For example:

```go
http.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("This was a GET request!"))
	})
http.HandleFunc("POST /", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("This was a POST request!"))
	})
```

So then if I perform a POST request:

```bash
curl -X POST http://localhost:8000
> This was a POST request!%  
```

And then just a GET request:

```bash
curl http://localhost:8000
This was a GET request!%  
```

That's a pretty powerful pattern-matcher to have straight out of the box. The only thing I'm less keen on is the `w.Write` syntax, but that's extremely minor. It'll be interesting to see how I get on.

[^1]: I still prefer Express-style pattern matching because inertia




