3.2 KiB
title | date | tags | excerpt | ||
---|---|---|---|---|---|
Learning Go: Day Seven | 2024-05-07T08:00:00.0Z |
|
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. 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. Like on day one, I initialised my Go module:
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 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":
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. It's not too dissimilar to most other URL pattern-matching libraries1. Generally the syntax is:
/
- match the root/something
- explictly match a URL/something-else/
- matching any URL where the path starts with/something-else/
/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:
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:
curl -X POST http://localhost:8000
> This was a POST request!%
And then just a GET request:
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.
-
I still prefer Express-style pattern matching because inertia ↩︎