---
title: Understanding Golang's Func Type
date: 2015-11-23
description: How Go's http.HandlerFunc adapter uses a func type to satisfy the Handler interface and enable flexible HTTP routing.
tags: [go]
---

## Introduction

Here is some code that demonstrates the typical 'hello world' for a Go based web server:

```go
package main

import (
  "fmt"
  "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "Hello %s", r.URL.Path[1:])
}

func main() {
  http.HandleFunc("/World", handler)
  http.ListenAndServe(":8080", nil)
}
```

> [!EXAMPLE]
> `http://localhost:8080/World` will return `Hello World`

For most people, setting up a web server to handle incoming HTTP requests is considered a quick and simple introduction to the [Go programming language](https://golang.org/), and looking at the above code it's easy to see why that would be the case. But further investigation can yield some nice learnings about Go's built-in `func` type and how it is used as an adapter layer.

In this blog post I will demonstrate a few different ways of creating a web server and then I'll clarify how some of the functionality (specifically `http.HandleFunc`) works. What initially drove me to look into this was my curiosity as to why I would always insert `nil` to the `http.ListenAndServe` function by default when setting up a basic web server (see above code example).

It was never really that clear to me and so it's just something I 'cargo cult'ed and subsequently replicated every single time I needed a web server. I realised I needed to know what its purpose was in order to feel like I wasn't going through the motions unnecessarily or missing out on additional functionality (which it turns out I was).

## Four ways to skin a cat

There are currently four ways, that I know of, to create a web server with Go (well, actually only three - the first two examples are effectively the same - but we add a little more code to demonstrate different ways incoming requests can be handled).

Each of the variations ultimately revolve around what we send to `http.ListenAndServe` as its second argument (and this 'thing' we send also ultimately should have a `ServeHTTP` method; we'll see shortly how this is achieved in different ways).

So here are each of the variations:

1. No request parsing (serve same content regardless of request)
1. Manual request parsing
1. Multiplexer
1. Global multiplexer

### No request parsing

The most basic implementation (and by basic I don't mean 'simplest', more... 'raw') is demonstrated in the below code sample, which calls `ListenAndServe` and passes in `db` as its second argument.

> [!INFO]
> although I wrote this blog post back in October 2015, I've rewritten the below examples based off inspiration from "The Go Programming" book I've been reading recently

This first section will give us enough background and grounding to build upon in the latter sections:

```go
package main

import (
  "fmt"
  "log"
  "net/http"
)

type pounds float32

func (p pounds) String() string {
  return fmt.Sprintf("£%.2f", p)
}

type database map[string]pounds

func (d database) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  for item, price := range d {
    fmt.Fprintf(w, "%s: %s\n", item, price)
  }
}

func main() {
  db := database{
    "foo": 1,
    "bar": 2,
  }

  log.Fatal(http.ListenAndServe("localhost:8000", db))
}
```

We can see from the above code sample that `db` is an instance of our custom `database` type, which states it should be a map data structure consisting of strings for keys and `pounds` for values.

We can also see that `pounds` is itself a type of `float32` and has a custom `String` method attached, allowing us to modify its output when converted into a string value. Similarly the `database` type has a method attached, but this time it is a `ServeHTTP` method.

The `ServeHTTP` is required in order to satisfy the `ListenAndServe` method signature, which states the second argument should be a type of `Handler`:

```go
func ListenAndServe(addr string, handler Handler) error
```

> [!TIP]
> Documentation: `godoc net/http ListenAndServe | less`

If we look at the source code for the `Handler` type (below) we can clearly see it requires a `ServeHTTP` method to be available (hence why our `database` type associates its own `ServeHTTP` method):

```go
type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}
```

> [!TIP]
> Documentation: `godoc net/http Handler | less`

The above sample web server code will always serve the same response regardless of the URL that was specified. So for example...

- `http://localhost:8000/`
- `http://localhost:8000/abc`
- `http://localhost:8000/xyz`

...will all serve back the response:

```
foo: £1.00
bar: £2.00
```

### Manual request parsing

OK, so now we've got the above example written. Let's enhance it by allowing our application to handle different routes as apposed to serving the same content all the time. To do this we'll modify our `ServeHTTP` method to interrogate the incoming request object and parse out the URL, as demonstrated in the below code sample:

```go
package main

import (
  "fmt"
  "log"
  "net/http"
)

type pounds float32

func (p pounds) String() string {
  return fmt.Sprintf("£%.2f", p)
}

type database map[string]pounds

func (d database) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  switch r.URL.Path {
  case "/foo":
    fmt.Fprintf(w, "foo: %s\n", d["foo"])
  case "/bar":
    fmt.Fprintf(w, "bar: %s\n", d["bar"])
  default:
    w.WriteHeader(http.StatusNotFound)
    fmt.Fprintf(w, "No page found for: %s\n", r.URL)
  }
}

func main() {
  db := database{
    "foo": 1,
    "bar": 2,
  }

  log.Fatal(http.ListenAndServe("localhost:8000", db))
}
```

Nothing else to say about this, other than we've implemented what we set out to do by utilising a simple `switch` statement that checks for known paths and writes to the `http.ResponseWriter` a different response depending on the request. If we can't match the URL then we'll instead send a `404` status code (`StatusNotFound`) followed by a message to notify the user we couldn't identify their request.

> [!TIP]
> Documentation: `godoc -src net/http WriteHeader | less`

### Multiplexer

So writing the above example demonstrates a bit of a code smell. We could extract each case's block into separate functions but it's still an ever growing switch statement. We're also confined to using objects that implement the required interface (e.g. if you don't provide an object that has a `ServeHTTP` method then you're not going to have much success).

Instead it would be nice if you could just pick an arbitrary function and allow it to be used as a handler. That's exactly what `ServeMux` provides to us via its `HandleFunc` function (which is really just a convenience method on top of `http.HandlerFunc`).

> [!TIP]
> Documentation: `godoc net/http ServeMux | less`

The following code sample demonstrates this in action, by removing the `ServeHTTP` method from the `database` type and instead implementing individual methods for our defined routes to call.

```go
package main

import (
  "fmt"
  "log"
  "net/http"
)

type pounds float32

func (p pounds) String() string {
  return fmt.Sprintf("£%.2f", p)
}

type database map[string]pounds

func (d database) foo(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "foo: %s\n", d["foo"])
}

func (d database) bar(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "bar: %s\n", d["bar"])
}

func (d database) baz(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "baz: %s\n", d["baz"])
}

func main() {
  db := database{
    "foo": 1,
    "bar": 2,
    "baz": 3,
  }

  mux := http.NewServeMux()

  mux.Handle("/foo", http.HandlerFunc(db.foo))
  mux.Handle("/bar", http.HandlerFunc(db.bar))

  // Convenience method for longer form mux.Handle
  mux.HandleFunc("/baz", db.baz)

  log.Fatal(http.ListenAndServe("localhost:8000", mux))
}
```

As we can see, we create a new `ServeMux` instance using `http.NewServeMux` and then register our `database` methods as handlers for each of the route's we want to match them against. The `ServeMux` instance is a multiplexer, meaning we can pass it as the second argument to `http.ListenAndServe`.

> [!INFO]
> you can also see we demonstrate the shorthand `mux.HandleFunc` which is really a convenience method over both `mux.Handle` and `http.HandlerFunc`

So how does `http.HandlerFunc` and `mux.HandleFunc` allow us to use an arbitrary function (as none of those database functions have access to a `ServeHTTP` function as required by `ListenAndServe`)? We'll come back to the answer in a little bit. Let's quickly review the last variation of how to run a web server first...

### Global multiplexer

Typically you'll have your code split up into separate packages. So in order to setup your routing handlers, you would need to pass around your `ServeMux` instance to each of these packages. Instead, you can just utilise Go's global `DefaultServeMux`. To do that you pass `nil` as the second argument to `http.ListenAndServe`.

> [!TIP]
> Documentation: `godoc -src net/http DefaultServeMux | less`

The following code sample demonstrates this:

```go
package main

import (
  "fmt"
  "log"
  "net/http"
)

type pounds float32

func (p pounds) String() string {
  return fmt.Sprintf("£%.2f", p)
}

type database map[string]pounds

func (d database) foo(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "foo: %s\n", d["foo"])
}

func (d database) bar(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "bar: %s\n", d["bar"])
}

func (d database) baz(w http.ResponseWriter, r *http.Request) {
  fmt.Fprintf(w, "baz: %s\n", d["baz"])
}

func main() {
  db := database{
    "foo": 1,
    "bar": 2,
    "baz": 3,
  }

  http.HandleFunc("/foo", db.foo)
  http.HandleFunc("/bar", db.bar)
  http.HandleFunc("/baz", db.baz)

  log.Fatal(http.ListenAndServe("localhost:8000", nil))
}
```

Again, we have a convenience method `HandleFunc` which allows an arbitrary function to be adapted so it fits the interface requirements that `ListenAndServe`'s second argument enforces.

## How does the adapter work?

The 'adapter' here being the `http.HandleFunc` function. How does it take an arbitrary function and enable it to support the relevant interface so it can be passed to `ListenAndServe`?

The way `http.HandleFunc` solves this requirement is by internally calling its *other* function `http.Handle`, and passing it the required type (i.e. it passes a type that satisfies the interface requirement that the `Handle` function has).

OK, let's look back at the two functions and their respective signatures to refresh our memory as to what's required:

- `func Handle(pattern string, handler Handler)`
- `func HandleFunc(pattern string, handler func(ResponseWriter, *Request))`

We can see the `Handle` signature requires a type that satisfies the `Handler` interface (which is defined as follows):

```go
type Handler interface {
  ServeHTTP(ResponseWriter, *Request)
}
```

In other words, as long as you pass in a type that has a `ServeHTTP` method then the `Handle` function will be happy. So `HandleFunc` facilitates this requirement by taking your user defined function and converting it into a type that happens to have `ServeHTTP` available.

So how does it do that conversion? Firstly it defines a `func` type called `http.HandlerFunc`, like so:

```go
type HandlerFunc func(ResponseWriter, *Request)
```

This says that for a function to match this type it should have the same signature (e.g. `ResponseWriter, *Request`).

Inside the `HandleFunc` function you'll see it actually *calls* this `func` type and passes it your user defined function. This will look something like the following in the Go implementation source code:

```go
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
  mux.Handle(pattern, HandlerFunc(handler))
}
```

Notice the call of `HandlerFunc(handler)` (where `handler` is your user defined function you passed into `HandleFunc` from your application code). This is the *conversion* of your function into the `HandlerFunc` type. You're now effectively passing a `HandlerFunc` into the internal function `mux.Handle`.

So how does that help us? How does passing in a function that *looks* like a `HandlerFunc` type into `mux.Handle` help us solve the problem that we're still passing in a function that has no `ServeHTTP` method available (and so should fail the interface requirement that `mux.Handle` has)?

Well, once you convert your user defined function into a `HandlerFunc` you'll find it now *does* have a `ServeHTTP` method available. If we look at the Go source code, just after the definition of the `HandlerFunc` func type, you'll also find the following snippet of code:

```go
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
  f(w, r)
}
```

This associates the required `ServeHTTP` function with the `HandlerFunc` type. So when you convert your function to a `HandlerFunc` it will indeed gain access to a `ServeHTTP` function!

Also remember that when you associate a method with a type/object the receiver is also available to you. So in this case we can see the `f` is actually your user defined function you passed in to be converted. So when you convert that user defined function into a `HandlerFunc` you get the `ServeHTTP` method which internally is calling your original user defined function.

Let's now take a quick look at that `mux.Handle` function to see what it expects:

```go
func (mux *ServeMux) Handle(pattern string, handler Handler) {
  ...
}
```

As we can see it expects a type of `Handler` to be provided. What is `Handler`? Well remember from earlier this is an interface which states there should be a `ServeHTTP` function available:

```go
type Handler interface {
  ServeHTTP(ResponseWriter, *Request)
}
```

We know now that we've utilised Go's `func` type to adapt/transform our incoming function into a type that has the required method `ServeHTTP` associated with it, thus allowing it to pass the `Handler` interface requirement.

## Why is this interesting?

Really understanding what initially looked to be a simple web server abstraction ended up being a complex mix of types and interfaces that work together to allow seemingly incompatible types to be adapted to fit. Demonstrating how flexible and dynamic your code can be when working in an idiomatic way with the Go principles.

I now have a much better appreciation of why lots of long time Gophers will routinely recommend sifting through the official Go source code, as it can indeed be quite enlightening.

## Summary/Breakdown

Here is a useful summary for you...

- `http.Handler` = interface

> [!INFO]
> you support `http.Handler` if you have a `ServeHTTP(w http.ResponseWriter, r *http.Request)` method available.

- `http.Handle("/", <give me something that supports the http.Handler interface>)`

> [!EXAMPLE]
> e.g. an object with a `ServeHTTP` method.

- `http.HandleFunc("/", <give me any function with the same signature as ServeHTTP >)`

> [!EXAMPLE]
> e.g. a function that accepts the arguments `(w http.ResponseWriter, r *http.Request)`.

- `http.HandlerFunc` = func type used internally by `http.HandleFunc`

> [!INFO]
> e.g. it adapts the given function to the `http.HandlerFunc` type, which has an associated `ServeHTTP` method (that is able to call your original incompatible function).
