building blocks of go services
Go has many web frameworks, but none that come with the standard library. There are many to choose from but this is a difficult problem. There are advantages to choosing a very well established framework, but also disadvantages like lock-in, support and flexibility. When you do not know what you will required from a framework in 3 / 6 / 9 months, how can you make that choice?
Instead of a built in framework, go provides a number of well thought out building blocks from which you can roll your own! These building blocks mean that frameworks are unnecessary to get you off the ground and are unnecessary when you find you need to add additional pieces to your apps.
ListenAndServe
ListenAndServe
listens on a TCP network address and will serve resquests on incoming connections.
It is defined as:
|
|
Example usage:
|
|
It’s the func that runs a webserver in a go application and takes and address (":8080"
) and a Handler
…
Handler
A Handler responds to an HTTP request.
|
|
The handler type is an interface with a single method ServeHTTP
. This method is called for each request recieved by ListenAndServe
and returning from this method means that the request has been handled and is finished. Inside the method, you can read from the *Request
and write to the ResponseWriter
You could define a type, and implement the Hander
interface and manage the request paths etc. yourself. But this quickly becomes messy…
|
|
Here, it may be a trivial example but we can see that in a real world app with complex logic required for each endpoint this will quickly get out of hand, but also that we can currently only handle GET
requests. Infact, the verb is not respected at all. Adding another nested switch on the supported verbs inside each case statement will make out ServeHTTP
function gross! We can also see that the endpoints
struct is not used, apart from to satisfy the interface.
HandlerFunc
The HandlerFunc type is an adapter to allow the use of ordinary functions as HTTP handlers. It implements the single method defined in the Handler
interface for you:
|
|
And calls the provided function f
with w
and r
, all you need to do is provide a function with a method signature that matches the ServeHTTP
function and the HandlerFunc
interface will turn it into a Handler
!
Using the same example from above you can now lose the unused endpoints
struct:
|
|
http.HanderFunc
is not a function call, it is a type conversion of the Endpoints
func to a func that implements the Handler
interface.
We have managed to remove the need for the endpoints
struct and replaced it with a single function that is type converted into a Handler
, but we still have the problems of request verbs and all the endpoints being listed in a switch in a single function.
HandleFunc
http.HandleFunc
registers a function as a handler for a single endpoint.
|
|
We have removed the need for mapping the url path inside a switch statement and offloaded that responsibility to the http
package. Now we need only write functions with the correct args and register them as handlers for the correct url paths.
What is the http
package actually doing?
Each call to http.HandleFunc
registers that function and path as a handler on the http
package’s DefaultServeMux
.
ServeMux
ServeMux
is an http multiplexer, it pattern matches the URL of requests and the specified handlers and calls the closet matching handler.
The DefaultServeMux
is a ServeMux
var exported from the http package. Using a ServeMux
and the HandleFunc
func we can far more easily and cleanly register endpoints for the web app. But we still do not have a means for handling http request methods, GET
, POST
, etc.
Our ServeMux
only respects the url path and not the method. It would be great if we could register a handler
for the url path and method.
GorillaMux
gorilla/mux is also an http multiplexer. It routes and dispatches http requests.
|
|
Very quickly it’s obvious that this is extremely useful for all the things that might be missing from the stdlib implementaiton of a request mutliplexer. There are too many awesome features to explain here, but checkout the docs.
Wrap Up
go has an awesome stadard library, and each building block plays it’s part. Understanding each of them allows us to more easily and maintainably create a web service in go, without reaching for an off the shelf framework, becuase you probably don’t need it!