Go言語でWebサイトを作ってみる （6: ユーザー情報をJSONから読み込んで参照してみる）

> すべての記事の一覧はこちら。
**Go言語でWebサイトを作ってみる：目次**
http://qiita.com/y_ussie/items/8fcc3077274449478bc9

前回の仕切り直し篇 http://qiita.com/y_ussie/items/12bb4fd8cefb740581f8 の続きになります。

一旦コードも整理できましたので、引き続き機能追加していきたいと思います。

# やりたいこと
次のステップとしては、

* ユーザー情報をJSONから読み込んで参照できるようにする
* ログイン画面からユーザーID/パスワードでログインできるようにする
* ログインユーザーしか見られないページを作ってみる

を実装してみたいと思います。

まずは手始めに、ユーザー情報をJSONから読み込んでみます。

# ユーザー情報のJSONデータ

ということで以下のJSONデータを作ってみました。

```JSON:data/users.json
[
    {
        "id": "806d5832-e253-40ca-be80-a00878898c37",
        "user_id": "a-chan",
        "password": "5f4dcc3b5aa765d61d8327deb882cf99",
        "full_name": "Nishiwaki Ayaka"
    },
    {
        "id": "e7bdce91-c9bb-4a29-91f8-750ad4b18bfa",
        "user_id": "kashiyuka",
        "password": "5f4dcc3b5aa765d61d8327deb882cf99",
        "full_name": "Kashino Yuka"
    },
    {
        "id": "b87c826e-429b-4f50-aa35-b99f11a40b08",
        "user_id": "nocchi",
        "password": "5f4dcc3b5aa765d61d8327deb882cf99",
        "full_name": "Omoto Ayano"
    }
]
```

フィールドは id, user_id, password, full_name です。
idはuuidv4にて生成した一意の値で、passwordはMD5ハッシュした文字列を使用しています。

このJSONを参照するためのモデルとデータアクセサの一式が以下の user.go になります。

https://github.com/yoshinoyaussie/golang-website-sample/blob/chapter-6/webserver/model/user.go

JSONを読み込むためのモデル構造体を以下のように定義しています。

```go:
// User はユーザーの情報を表します。
type User struct {
	ID       ID        `json:"id"`
	UserID   string    `json:"user_id"`
	Password StringMD5 `json:"password"`
	FullName string    `json:"full_name"`
}

// 情報をメモリ上に持つためのmap
var users map[ID]User
```

この構造体に、以下の処理にてJSONデータを読み込んでいます。

```go:
func (a *UserDataAccessor) decodeJSON() error {
	// JSONファイル読み込み
	bytes, err := ioutil.ReadFile("data/users.json")
	if err != nil {
		return err
	}
	// JSONをデコードする
	var records []User
	if err := json.Unmarshal(bytes, &records); err != nil {
		return err
	}
	// 結果をmapにセットする
	for _, x := range records {
		users[x.ID] = x
	}
	return nil
}
```

読み込んだJSONデータをリクエストハンドラから参照するために、データアクセサとして UserDataAccessor という構造体を作成しています。
これは http://qiita.com/y_ussie/items/b1db86b0b54ec69bb928 で作成したセッションデータストアと同様に、mapへのアクセスは1本の Goroutine でデータ操作を逐次処理化しておいて、外からは Channel でアクセスする作りになっています。

今回は読み込みのみですのでここまでの処理は必要ないのですが、すぐに追加・更新・削除の処理も作成する予定ですので、そのあたり考慮しています。
ただ、今後データモデルが増えるたびに仰々しく実装するのは大変ですので、次にデータモデルを増やす際にモデル共通の処理はまとめて、モデル毎の実装量を減らすようリファクタリングしていこうと思います。

# リクエストハンドラ側の処理

今回は、以下のリクエストハンドラを追加します。

## GET /users/:user_id

「:user_id」というパスパラメータを使用して、ユーザーIDで検索したユーザー情報を表示します。
リクエストハンドラの処理は以下のようになりました。

```go:
// GET:/users/:id
func handleUsersGet(c echo.Context) error {
	users, err := userDA.FindByUserID(c.Param("user_id"), model.FindFirst)
	if err != nil {
		return c.Render(http.StatusOK, "error", err)
	}
	user := users[0]
	return c.Render(http.StatusOK, "user", user)
}
```

```html:templates/user.html
{{define "content"}}
<h2>User Detail</h2>
<table>
<tr>
<th width="100px">User ID</th><td>{{.UserID}}</td>
</tr>
<tr>
<th width="100px">Full Name</th><td>{{.FullName}}</td>
</tr>
</table>
{{end}}

```

パスパラメータは、Echoでは echo.Context#Param(<パラメータ名>) で取得できます。
取得したパラメータを、データアクセサに用意した FindByUserID() に渡して検索しています。
結果は User の配列で返ります。

# 実行結果

## GET /users/:user_id

指定したユーザーIDが存在する場合、ユーザーIDとフルネームが表示されます。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/70686/09387579-d062-a988-17a7-99a583105dff.png)

存在しないユーザーIDを指定した場合にはこのようにエラー表示されます。

![2.png](https://qiita-image-store.s3.amazonaws.com/0/70686/9928bf37-f16f-de40-20ba-0ec660949d54.png)

# 今回使用したコードについて

今回使用したコードの一式は以下の GitHub に置いてあります。
https://github.com/yoshinoyaussie/golang-website-sample/tree/chapter-6


# 次回予定

引き続き、今回作成したユーザー情報参照の仕組みを使用して、ログイン画面およびログインユーザーしか見られないページを作成してみます。