Web servers in Golang
There are a few ways to write backends (web servers) in golang.
There’s the net/http
package in the standard library, but there’s also 3rd party libraries:
- chi: lightweight, idiomatic and composable router for building Go HTTP services
- gorilla: A helpful toolkit for the Go programming language that provides useful, composable packages for writing HTTP-based applications.
- echo: High performance, minimalist Go web framework
- huma: Huma REST/HTTP API Framework for Golang with OpenAPI 3.1
They all have different features and tradeoffs, but we will be using the built-in net/http
because it is one less thing to learn,
even if it means we have to write more boilerplatey code.
The basics
Here is a basic example
log.Fatal
is equivalent tolog.Print
followed by a call to os.Exit(1).
http.ListenAndServe(":8080", nil)
listens on the TCP network address 8080 and then calls Serve with handler to handle requests on incoming connections. Accepted connections are configured to enable TCPkeep-alive
s.The handler is typically nil, in which case DefaultServeMux is used.
ListenAndServe always returns a non-nil error.
If you run go run main.go
, you should see nothing. Let’s add some functionality.
Routers and handlers
In basically every framework, we write a function that gets associated with a path and one or more HTTP methods. See this table as an example.
Function | Path |
---|---|
say_hello | GET /hello |
version | GET /version |
login | POST /auth/login |
This mapping is done by something normally call a router (in Go, they are called ServeMux
).
It routes the request to the correct function.
These functions are sometimes called handlers, because they handle HTTP requests.
Let’s add a ServeMux
and a handler to our go program, and lets also print something out just so we know its working.
You need to stop (ctrl+c) and restart the server whenever you make changes to your code. We will address this soon.
If you go to http://localhost:8080/hello in your browser, you should see “hello world”.
There’s no reason we have to make it a separate function though. Go supports anonymous functions, which leads to locality of behavior, something that is useful when developing larger projects.
This pattern, however, makes it so that testing the individual handlers is impossible. I argue that testing handlers individually isn’t useful, and you should try to end-to-end test wherever you can. We will cover testing much later.
Path parameters and error handling
Go provides a way for you to include data as part of the path, e.g. /customer/1234
.
We can specify a route has a path parameter with the {name}
syntax, e.g. /customer/{id}
.
If you go to http://localhost:8080/customer/1234, you should see “hello customer 1234”
- http://localhost:8080/customer/asdf should respond with “Invalid customer id: asdf”
- http://localhost:8080/customer/1235 should respond with “404 page not found”
State
Our API need to “remember” things: the current todos, the current user, the who is logged in. This API specific memory is called state.
reworded from https://react.dev/learn/state-a-components-memory
We can introduce some state in the form of a global variable.
If you go to http://localhost:8080/count, you should see 0. However, if you go to http://localhost:8080/count/increment, you should see “Method not allowed”.
This because we specified the POST method for the /count/increment
and /count/reset
Notice how when we want to get the current count, we use the GET HTTP method, but when we want to change it, we use the POST method. The method conveys intent from the client to the server, and also allows for stuff like caching.
If instead of returning the count, we had to do some calculation, we could save ourselves from doing the calculation again (caching it) if the count didn’t change. However, we can’t cache an ‘increment’. We always have to add one when we get a request to POST /count/increment
What is state?
- a subdivision of a country
Which of these is not a HTTP method?
- PATCH
- OPTIONS
- UPDATE
- HEAD
What is a route?
What is a handler?
What is a router?