(go lang) HandleFunc のメモ / APIコード解読 その１

##0. 超シンプルなAPIのコードを読む

```go:main.go
package main

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

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
	})

	log.Fatal(http.ListenAndServe(":8080", nil))
}
```
- `go run main.go`で実行
- ブラウザで`localhost:8080`を叩く。

##1. 解読メモ

####1-1. [http.HandleFunc](https://golang.org/pkg/net/http/#HandleFunc)
```go
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
```
- handlerを定義し、ServerMuxに登録する関数.
  - handler : (リクエストURLのパターンマッチと、マッチしたリクエストに対する応答が定義)
  - ServerMux : (パターンマッチで適合したリクエストに対して、そのパターンマッチを持つhandlerを呼び出してくれる)

####1-2. http.ResponseWriter
- リクエストに対するレスポンスを作るためのインターフェース

####1-3. *http.Request
- Serverが受け取ったhttpリクエストを扱うためにnet/httpパッケージで用意されている構造体

####1-4. http.ListenAndServe
```go
func ListenAndServe(addr string, handler Handler) error
```

- 第1引数で指定された[TCPアドレス:ポート]をListenし、第2引数で指定したhandlerを提供する。
- 上述のコードのように、handlerが`nil`を指定された場合はデフォルトのServerMuxが使われる。

##2. 書き換え
- 以上を踏まえて次のように書き換えてみる

```go

package main

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

func main() {
	http.HandleFunc("/", fooooServer)
	log.Fatal(http.ListenAndServe(":8080", nil))

}

func fooooServer(w http.ResponseWriter, r *http.Request) {
       fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
}

```

- 単にhandlerに名前(fooooServer)を付けて、別途取り出してみただけ。でもコードが長くなる時などはこっちの方が分かりやすそう。。

##3. その他のメモ、疑問解決
####3-1. ResponseWriterインターフェースに値を入れるときに、fmt.Fprintfが使えるのはどうして？
- ResponseWriterの説明を読むと、以下のようになっている

```go
type ResponseWriter interface {
    Header() Header
    Write([]byte) (int, error)
    WriteHeader(int)
}
```
なので、素直に考えると、

```go
 fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
```
ではなくて

```go
w.Write([]byte("hello, " + r.URL.Path))
```

となる。
しかし、例えば[stackoverflowのこのページ](http://stackoverflow.com/questions/37863374/whats-the-difference-between-responsewriter-write-and-io-writestring)でも議論されているように、Fprintfの第1引数はio.Writerというインタフェースが使われていて、これは以下のような作りになっているらしい。

```go
type Writer interface {
    Write(p []byte) (n int, err error)
}
```

つまりバイト型のスライスからstringへの変換は自動でやってくれるからfmt.Fprintfなどを使った方がベターなんだと。

####3-2. Request構造体を見学
- サンプルをいじってRequest構造体を構成する要素を色々出力させて見る

```go
type Request struct {
        // For client requests an empty string means GET.
        Method string

        // URL specifies either the URI being requested (for server
        // requests) or the URL to access (for client requests).
        URL *url.URL

        // The protocol version for incoming server requests.
        Proto      string // "HTTP/1.0"
        ProtoMajor int    // 1
        ProtoMinor int    // 0

        // Header contains the request header fields either received
        // by the server or to be sent by the client.
        Header Header

        // Body is the request's body.
        Body io.ReadCloser
        ContentLength int64
        TransferEncoding []string
        Close bool
        Host string

        Form url.Values
        PostForm url.Values
        MultipartForm *multipart.Form
        Trailer Header
        RemoteAddr string
        RequestURI string
        TLS *tls.ConnectionState
        Cancel <-chan struct{}
        Response *Response
}
```
たくさんある。

```go
 fmt.Fprintf(w, "%q", html.EscapeString(r.Proto))
// HTTP/1.1と出る
```

```go
 fmt.Fprintf(w, "%q", html.EscapeString(r.Method))
// GETと出る。リクエストメソッドがnilだったらGETだと解釈している
```

Headerはmap構造になっている。

```go
 fmt.Fprintf(w, "%q", html.EscapeString(Header["Accept-Language"]))
// [en-US,en;q=0.5]と出る。
```

```go
 fmt.Fprintf(w, "%q", html.EscapeString(Header["Cache-Control"]))
// [max-age=0]と出る。
```


```go
 fmt.Fprintf(w, "%q", html.EscapeString(r.Close))
// falseと出る。レスポンスを返した後もコネクションクローズしない。
```

```go
 fmt.Fprintf(w, "%q", html.EscapeString(r.RequestURI))
// '/'と出る
```

```go
 fmt.Fprintf(w, "%q", html.EscapeString(r.Host))
// localhost:8080と出る
```