Go言語のWebフレームワーク「Echo」を使ってみる ②（リクエストパラメータの扱い）

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

前回のHello World篇 http://qiita.com/y_ussie/items/ca8dc5e423eec318a436 の続きです。

今回はリクエストパラメータの取得を試してみます。
前回のHello World篇では「Hello World」をHTMLとJSONで出力しましたが、この文字列の「World」の部分をリクエストパラメータで渡すようにしてみます。

パラメータを受け取る方法については、以下の3種に対応します。

* クエリーパラメータ（GET）
* フォーム（POST）
* JSON（POST）

#やりたいこと
以下のリクエストを処理する。
## GET /hello?greetingto=xxx

クエリーパラメータで受け取った「greetingto」パラメータをテンプレートに埋め込み、
Hello xxx!
の文字列をHTMLで出力する。

## GET /api/hello?greetingto=xxx
クエリーパラメータで受け取った「greetingto」パラメータより、
以下のJSONを返す。

```JSON
{"hello": "xxx"}
```

## GET /hello_form
以下のフォームを出力する。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/70686/9e1d5339-ee93-0bdf-1a50-54d45af9b76d.png)


HTMLテンプレートは以下のようなコード。

```html:template/hello_form.html
{{define "content"}}
<form action="/hello" method="POST">
    <label for="greetingto">Greeting To: </label>
    <input type="text" id="greetingto" name="greetingto" />
    <input type="submit" />
</form>
{{end}}
```


## POST /hello
hello_formよりPOSTされた「greetingto」パラメータをテンプレートに埋め込み、
Hello xxx!
の文字列をHTMLで出力する。

## POST /api/hello
POSTされた以下のJSON

```JSON
{"greetingto": "xxx"}
```

より取得した「greetingto」パラメータより、
以下のJSONを返す。

```JSON
{"hello": "xxx"}
```

# 前回のコードに追加してみた。

```go:main.go
package main

import (
	"html/template"
	"io"
	"net/http"

	"github.com/labstack/echo"
	"github.com/labstack/echo/middleware"
)

// レイアウト適用済のテンプレートを保存するmap
var templates map[string]*template.Template

// Template はHTMLテンプレートを利用するためのRenderer Interfaceです。
type Template struct {
}

// Render はHTMLテンプレートにデータを埋め込んだ結果をWriterに書き込みます。
func (t *Template) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
	return templates[name].ExecuteTemplate(w, "layout.html", data)
}

func main() {
	// Echoのインスタンスを生成
	e := echo.New()

	// テンプレートを利用するためのRendererの設定
	t := &Template{}
	e.Renderer = t

	// ミドルウェアを設定
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	// 静的ファイルのパスを設定
	e.Static("/public/css/", "./public/css")
	e.Static("/public/js/", "./public/js/")
	e.Static("/public/img/", "./public/img/")

	// 各ルーティングに対するハンドラを設定
	e.GET("/", HandleIndexGet)
	e.GET("/hello", HandleHelloGet)
	e.POST("/hello", HandleHelloPost)
	e.GET("/hello_form", HandleHelloFormGet)
	e.GET("/api/hello", HandleAPIHelloGet)
	e.POST("/api/hello", HandleAPIHelloPost)

	// サーバーを開始
	e.Logger.Fatal(e.Start(":3000"))
}

// 初期化を行います。
func init() {
	loadTemplates()
}

// 各HTMLテンプレートに共通レイアウトを適用した結果を保存します（初期化時に実行）。
func loadTemplates() {
	var baseTemplate = "templates/layout.html"
	templates = make(map[string]*template.Template)
	templates["hello"] = template.Must(
		template.ParseFiles(baseTemplate, "templates/hello.html"))
	templates["hello_form"] = template.Must(
		template.ParseFiles(baseTemplate, "templates/hello_form.html"))
}

// HandleIndexGet は Index のGet時のHTMLデータ生成処理を行います。
func HandleIndexGet(c echo.Context) error {
	return c.Render(http.StatusOK, "hello", "world")
}

// HandleHelloGet は /hello のGet時のHTMLデータ生成処理を行います。
func HandleHelloGet(c echo.Context) error {
	greetingto := c.QueryParam("greetingto")
	return c.Render(http.StatusOK, "hello", greetingto)
}

// HandleHelloPost は /hello のPost時のHTMLデータ生成処理を行います。
func HandleHelloPost(c echo.Context) error {
	greetingto := c.FormValue("greetingto")
	return c.Render(http.StatusOK, "hello", greetingto)
}

// HandleHelloFormGet は /hello_form のGet時のHTMLデータ生成処理を行います。
func HandleHelloFormGet(c echo.Context) error {
	return c.Render(http.StatusOK, "hello_form", nil)
}

// HandleAPIHelloGet は /api/hello のGet時のJSONデータ生成処理を行います。
func HandleAPIHelloGet(c echo.Context) error {
	greetingto := c.QueryParam("greetingto")
	return c.JSON(http.StatusOK, map[string]interface{}{"hello": greetingto})
}

// HelloParam は /api/hello が受けとるJSONパラメータを定義します。
type HelloParam struct {
	GreetingTo string `json:"greetingto"`
}

// HandleAPIHelloPost は /api/hello のPost時のJSONデータ生成処理を行います。
func HandleAPIHelloPost(c echo.Context) error {
	param := new(HelloParam)
	if err := c.Bind(param); err != nil {
		return err
	}
	return c.JSON(http.StatusOK, map[string]interface{}{"hello": param.GreetingTo})
}
```

前回のコードをベースに今回の機能を追加してみました。
主に増えているのはフォームの表示のハンドラ HandleHelloFormGet() とPOST用のハンドラ 
 HandleHelloPost(), HandleAPIHelloPost() です。

HandleHelloGet() と HandleAPIHelloGet() には、クエリーパラメータの処理が増えています。
クエリーパラメータは echo.Context#QueryParam() で取得できます。

HandleHelloPost() は、フォームパラメータのPOSTを受ける処理です。
フォームパラメータは、echo.Context#FormValue() で取得できます。

HandleAPIHelloPost() は、JSONのPOSTを受ける処理です。
POSTされたJSONパラメータを取得するには、まずJSONを受け取るための構造体を用意しておき、構造体を
 echo.Context#Bind() することで構造体のメンバとして取得できます。

# 実行結果

## POST /hello

![2.png](https://qiita-image-store.s3.amazonaws.com/0/70686/4fa2a6b2-28e1-2e6b-b824-f4ff99540ab5.png)

## POST /api/hello

![3.png](https://qiita-image-store.s3.amazonaws.com/0/70686/802ac0f4-799f-d895-0dad-da8f9ae344d8.png)

# 次回予定

Cookieでも試してみますか。。