Nuxt と Go で Software Architecture の実験 ~1日目 Static Server編~

## はじめに
Software Architecture について学ぼうとした矢先に、[Nuxt.js(Vue.js)とGoでSPA + API(レイヤードアーキテクチャ)でチャットアプリを実装してみた](https://qiita.com/Sekky0905/items/3b7554d23a1a2cbc5cd7)という記事をみつけ、とても勉強になったため、１から自分でも実装してみることにしました。

これはその日記です。1日目はNuxtとGoで簡易的なstatic serverを作成しました。

## NuxtのSkeletonの作成

client folerの配下に、nuxt_go_template folderを作成し、その中でnuxtをインストールします。

```shell
$ yarn create nuxt-app <project-name>
```

## GoでSkeletonサーバ (static server) の作成

まずは、依存関係管理ツールのdepをインストールします（詳しくはこの[記事](https://qiita.com/Azizjan/items/66564b5dc7597717932b)を参考にしてください。）。

```shell
$ cd server
$ dep init
```

次に、server folder下にインフラ層を担当するinfra folderを作成し、さらにその配下に、routing技術を担当するrouter folderを作成します。

router folderの配下に、router.goを設置し、gorilla muxと呼ばれるhttp request multiplexerのpackageを利用してルーターをインスタンス化します。 

```go:router.go
package router

import (
	"github.com/gorilla/mux"
)

// Router is the gorilla router for API.
var Router *mux.Router

func init() {
	// Instantiation for gorilla Router.
	r := mux.NewRouter()

	Router = r
}

```

server配下のmain.goには静的ファイルをホスティングするサーバーを構築します。

```go:main.go
package main

import (
	"net/http"

	"github.com/hideUW/nuxt_go_template/server/infra/router"
)

func main() {
	// rootに対してnuxtのindex.htmlを返すように設定する。(ServeFile)
	entrypoint := "../client/nuxt_go_template/dist/index.html"
	router.Router.Path("/").HandlerFunc(ServeStaticFile(entrypoint))

	// 静的ファイルの提供
	// $PROROOT/_nuxt/　以下のファイルに http://localhost:8080/_nuxt/~.html でアクセスできるように設定する。(FileServer)
	router.Router.PathPrefix("/_nuxt/").Handler(
		http.StripPrefix("/_nuxt/", http.FileServer(http.Dir("../client/nuxt_go_template/dist/_nuxt/"))))

	// エラーハンドリング
	if err := http.ListenAndServe(":8080", router.Router); err != nil {
		panic(err.Error())
	}
}

// 静的ファイルをホスティングする。
func ServeStaticFile(entrypoint string) func(w http.ResponseWriter, r *http.Request) {
	fn := func(w http.ResponseWriter, r *http.Request) {
		http.ServeFile(w, r, entrypoint)
	}
	return http.HandlerFunc(fn)
}
```
[Goのhttp.Handlerやhttp.HandlerFuncをちゃんと理解する](https://journal.lampetty.net/entry/understanding-http-handler-in-go)という記事を参考にすると以下のように動作している事がわかります。

### http.Hundler

http.Handlerは```ServeHTTP```というメソッドを定義しているinterfaceです。このServeHTTPメソッドはHTTPリクエストを受けてHTTPレスポンスを返します。

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

http.ServeMux のHandleメソッドの引数がこのinterface型になっています。

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

### HandlerFunc

* func(ResponseWriter, *Request) を別の型として定義したものです。
* このHandlerFunc型にはServeHTTP(ResponseWriter, *Request)メソッドが実装されています。func(http.ResponseWriter, *http.Request) のシグネチャの関数を自分で定義しておき、このHandlerFuncにキャストするだけで構造体を宣言することなく http.Handler を実装することができます。

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

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}
```

```go
func hello(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "Hello World")
}

func main() {
    mux := http.NewServeMux()
    mux.Handle("/hello", http.HandlerFunc(hello)) // helloをHandlerFuncにキャスト
}
```

* helloをhttp.HandlerFuncにキャストしています。
* http.HandlerFuncは ServeHTTP を実装しているので、ServeMux.Handleの第2引数に指定することが可能です。

## おわりに

以下のコマンドを実行すると、Nuxtのindex.htmlが表示されて、ローカルホストを利用したstatic severが完成している事がわかります。

```shell
$ cd server
$ go run main.go
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182922/2aa4b8c4-6655-85f3-3d17-32ec332cc802.png)

明日もがんばります。