net/httpとfasthttpの対応表

# はじめに
どうも！みなさんこんにちは！
Go言語楽しんでますか？

最近，Go言語を使ったとあるインターンに参加したのですが，
そこでnet/httpに取って代わるかもしれない
fasthttpというパケージに触れる機会があったので，
今回は対応表という形でまとめたいと思います．

# fasthttpとは
go言語でHTTP通信を行うためのライブラリです．

go言語の標準パッケージでは[net/http](https://golang.org/pkg/net/http/)がすでに用意されているのですが，
[fasthttp](https://github.com/valyala/fasthttp)では標準パッケージを凌駕する処理の速さで一時期有名になりました．
公式のベンチマークでは，従来に比べ10倍の差がでたようです．

fasthttpのインストール
```go get -u github.com/valyala/fasthttp```
# 対応表

## サーバの起動
### net/http
```go:net/http
package main

import (
	"fmt"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprint(w, "Hello net/http!!")
}

func main() {
	// "/"に対しての処理
	http.HandleFunc("/", handler)

	// 8080でサーバを起動
	http.ListenAndServe(":8080", nil)
}

```
### fasthttp
```go:fasthttp
package main

import (
	"fmt"
	"github.com/valyala/fasthttp"
)

func handler(ctx *fasthttp.RequestCtx) {
	fmt.Fprint("Hello fasthttp!!")
}

func main() {
	requestHandler := func(ctx *fasthttp.RequestCtx) {
		// ctx.Path()がnet/httpでいうr.URL.Pathにあたる
		switch string(ctx.Path()) {
		// "/"に対しての処理
		case "/":
			handler(ctx)
		default:
			ctx.Error("Unsupported path", fasthttp.StatusNotFound)
		}
	}
	// 8080でサーバを起動
	fasthttp.ListenAndServe(":8080", requestHandler)
}

```

## エラーハンドリング
### net/http

```go:net/http
if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal(err)
}

```

### fasthttp
```go:fasthttp
if err := fasthttp.ListenAndServe(":8080", requestHandler); err != nil {
		log.Fatal(err)
}

```
## クエリ

以下のURLのクエリからそれぞれの値を取得
http://localhost:8080?name=satto&age=24
### net/http

```go:net/http
func handler(w http.ResponseWriter, r *http.Request) {
	// クエリはr.URL.Query().Get("key")で取得可能
	name := r.URL.Query().Get("name")
	age := r.URL.Query().Get("age")
	fmt.Fprintf(w, "name: %s age: %s\n", name, age)
}

/*===============省略==================*/
```

### fasthttp
```go:fasthttp
func handler(ctx *fasthttp.RequestCtx) {
	// クエリはctx.QueryArgs().Peek("key")で取得可能
	// stringでアスキーコードを文字に変換
	name := string(ctx.QueryArgs().Peek("name"))
	age := string(ctx.QueryArgs().Peek("age"))
	fmt.Fprintf(ctx, "name: %s age: %s\n", name, age)
}

/*===============省略==================*/
```

## POST
JSONをPOSTするとJSONが返ってくる簡単なAPIサーバ

### net/http

```go:net/http
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

type Input struct {
	In string
}

type Output struct {
	Out string
}

func jsonHandleFunc(w http.ResponseWriter, r *http.Request) {
	// outputの用意
	output := Output{"( ・`ω・´)"}
	outjson, err := json.Marshal(output)
	if err != nil {
		fmt.Println(err)
	}
	w.Header().Set("Content-Type", "application/json")
	fmt.Fprint(w, string(outjson))

	// POSTされたときの処理
	// ボディーの中身をチェック
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		output.Out = err.Error()
		fmt.Println(err.Error())
		return
	}
	input := Input{}
	// bodyの中身(JSON)をinputに流し込む
	err = json.Unmarshal(body, &input)
	if err != nil {
		output.Out = err.Error()
		fmt.Println(err.Error())
		return
	}
}

func main() {
	// 例 localhost:8080/json にJSONをPOSTするとJSONが返ってくる
	http.HandleFunc("/json", jsonHandleFunc)

	// 8080でサーバを起動
	http.ListenAndServe(":8080", nil)
}
```
### fasthttp

```go:fasthttp
package main

import (
	"encoding/json"
	"fmt"
	"github.com/valyala/fasthttp"
)

type Input struct {
	In string
}

type Output struct {
	Out string
}

func jsonHandleFunc(ctx *fasthttp.RequestCtx) {
	// outputの用意
	output := Output{"( ・`ω・´)"}
	// output用のJSON作成
	outjson, err := json.Marshal(output)
	if err != nil {
		fmt.Println(err)
	}
	ctx.Response.Header.Set("Content-Type", "application/json")
	fmt.Fprint(ctx, string(outjson))

	// POSTされたときの処理
	// ボディーの中身を取得
	body := ctx.PostBody()
	input := Input{}
	// bodyの中身(JSON)をinputに流し込む
	err = json.Unmarshal(body, &input)
	if err != nil {
		output.Out = err.Error()
		fmt.Println(err.Error())
		return
	}
}

func main() {
	requestHandler := func(ctx *fasthttp.RequestCtx) {
		switch string(ctx.Path()) {
		// 例 localhost:8080/json にJSONをPOSTするとJSONが返ってくる
		case "/json":
			jsonHandleFunc(ctx)
		default:
			ctx.Error("Unsupported path", fasthttp.StatusNotFound)
		}
	}
	// 8080でサーバを起動
	fasthttp.ListenAndServe(":8080", requestHandler)
}

```

### 実際にcurlで叩いてみる

```bash
$ curl -H "Content-type: application/json" -X POST -d '{"In": "(´・ω・｀)"}' http://localhost:8080/json
```

### 結果

```bash
$ {"Out":"( ・`ω・´)"}
```

## 静的ファイル配信

### ディレクトリ構造

```bash
.
├── main.go
└── static
    └── index.html
```

http://localhost:8080 にアクセスするとstaticディレクトリのindex.htmlの内容が表示される

### net/http

```go:net/http
package main

import (
	"net/http"
)

func main() {
	// 静的ファイル配信
	// カレントディレクトリにあるstaticの中身を配信
	http.Handle("/", http.FileServer(http.Dir("static")))

	// 8080でサーバを起動
	http.ListenAndServe(":8080", nil)
}
```
### fasthttp

```go:fasthttp
package main

import (
	"github.com/valyala/fasthttp"
)

func main() {
	// fsは静的ファイルを配信するために必要な設定を表す
	var fs fasthttp.FS
	requestHandler := func(ctx *fasthttp.RequestCtx) {
		switch string(ctx.Path()) {
		case "/":
			// カレントディレクトリにあるstaticのindex.htmlを配信
			fs = fasthttp.FS{
				Root: "./static",
				// ファイルを指定してあげないと読み込まれない
				IndexNames: []string{"index.html"},
			}
		default:
			ctx.Error("Unsupported path", fasthttp.StatusNotFound)
		}
		// 静的ファイルを配信するためのリクエストハンドラを作成
		fsHandler := fs.NewRequestHandler()
		fsHandler(ctx)
	}
	// 8080でサーバを起動
	fasthttp.ListenAndServe(":8080", requestHandler)
}

```

## ステータスコード
ほとんど変わりません

|ステータスコード|fasthttp|net/http|
|:-----------|:------------|:---------------|
|100|fasthttp.StatusContinue|http.StatusContinue|
|101|fasthttp.StatusSwitchingProtocols|http.StatusSwitchingProtocols|
|102|fasthttp.StatusProcessing|http.StatusProcessing|
|200|fasthttp.StatusOK|http.StatusOK|
|201|fasthttp.StatusCreated|http.StatusCreated|
|202|fasthttp.StatusAccepted|http.StatusAccepted|
|203|fasthttp.StatusNonAuthoritativeInfo|http.StatusNonAuthoritativeInfo|
|204|fasthttp.StatusNoContent|http.StatusNoContent|
|205|fasthttp.StatusResetContent|http.StatusResetContent|
|206|fasthttp.StatusPartialContent|http.StatusPartialContent|
|207|fasthttp.StatusMultiStatus|http.StatusMultiStatus|
|208|fasthttp.StatusAlreadyReported|http.StatusAlreadyReported|
|226|fasthttp.StatusIMUsed|http.StatusIMUsed|
|300|fasthttp.StatusMultipleChoices|http.StatusMultipleChoices|
|301|fasthttp.StatusMovedPermanently|http.StatusMovedPermanently|
|302|fasthttp.StatusFound|http.StatusFound|
|303|fasthttp.StatusSeeOther|http.StatusSeeOther|
|304|fasthttp.StatusNotModified|http.StatusNotModified|
|305|fasthttp.StatusUseProxy|http.StatusUseProxy|
|306|fasthttp._|
|307|fasthttp.StatusTemporaryRedirect|http.StatusTemporaryRedirect|
|308|fasthttp.StatusPermanentRedirect|http.StatusPermanentRedirect|
|400|fasthttp.StatusBadRequest|http.StatusBadRequest|
|401|fasthttp.StatusUnauthorized|http.StatusUnauthorized|
|402|fasthttp.StatusPaymentRequired|http.StatusPaymentRequired|
|403|fasthttp.StatusForbidden|http.StatusForbidden|
|404|fasthttp.StatusNotFound|http.StatusNotFound|
|405|fasthttp.StatusMethodNotAllowed|http.StatusMethodNotAllowed|
|406|fasthttp.StatusNotAcceptable|http.StatusNotAcceptable|
|407|fasthttp.StatusProxyAuthRequired|http.StatusProxyAuthRequired|
|408|fasthttp.StatusRequestTimeout|http.StatusRequestTimeout|
|409|fasthttp.StatusConflict|http.StatusConflict|
|410|fasthttp.StatusGone|http.StatusGone|
|411|fasthttp.StatusLengthRequired|http.StatusLengthRequired|
|412|fasthttp.StatusPreconditionFailed|http.StatusPreconditionFailed|
|413|fasthttp.StatusRequestEntityTooLarge|http.StatusRequestEntityTooLarge|
|414|fasthttp.StatusRequestURITooLong|http.StatusRequestURITooLong|
|415|fasthttp.StatusUnsupportedMediaType|http.StatusUnsupportedMediaType|
|416|fasthttp.StatusRequestedRangeNotSatisfiable|http.StatusRequestedRangeNotSatisfiable|
|417|fasthttp.StatusExpectationFailed|http.StatusExpectationFailed|
|418|fasthttp.StatusTeapot|http.StatusTeapot|
|422|fasthttp.StatusUnprocessableEntity|http.StatusUnprocessableEntity|
|423|fasthttp.StatusLocked|http.StatusLocked|
|424|fasthttp.StatusFailedDependency|http.StatusFailedDependency|
|426|fasthttp.StatusUpgradeRequired|http.StatusUpgradeRequired|
|428|fasthttp.StatusPreconditionRequired|http.StatusPreconditionRequired|
|429|fasthttp.StatusTooManyRequests|http.StatusTooManyRequests|
|431|fasthttp.StatusRequestHeaderFieldsTooLarge|http.StatusRequestHeaderFieldsTooLarge|
|451|fasthttp.StatusUnavailableForLegalReasons|http.StatusUnavailableForLegalReasons|
|500|fasthttp.StatusInternalServerError|http.StatusInternalServerError|
|501|fasthttp.StatusNotImplemented|http.StatusNotImplemented|
|502|fasthttp.StatusBadGateway|http.StatusBadGateway|
|503|fasthttp.StatusServiceUnavailable|http.StatusServiceUnavailable|
|504|fasthttp.StatusGatewayTimeout|http.StatusGatewayTimeout|
|505|fasthttp.StatusHTTPVersionNotSupported|http.StatusHTTPVersionNotSupported|
|506|fasthttp.StatusVariantAlsoNegotiates|http.StatusVariantAlsoNegotiates|
|507|fasthttp.StatusInsufficientStorage|http.StatusInsufficientStorage|
|508|fasthttp.StatusLoopDetected|http.StatusLoopDetected|
|510|fasthttp.StatusNotExtended|http.StatusNotExtended|
|511|fasthttp.StatusNetworkAuthenticationRequired|http.StatusNetworkAuthenticationRequired|