【Go言語】WebフレームワークBeegoを使ってフォームをPOST送信してみる

Go言語のフルスタックなWebフレームワーク`Beego`を使ったフォームアプリケーションを作成します。

# サンプル
#### フォーム画面を起動します。
![Beegoフォーム送信前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/f26ace16-5b82-c45e-314e-8cc06b7d5f59.png)

#### 名前、メールアドレス、おパスワードを入力して、送信ボタンをクリックします。
![Beegoフォーム祖入力.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/85ca12a0-d8e0-7e49-128d-99160ffecc4b.png)

#### デバッグはこのようにちゃんとPOST送信されていますね。
![Beegoデバッグ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/91e3fd88-459d-fd29-caeb-b428e1b01a58.png)

#### 画面コンソールでは、サーバから受け取ったデータが取得出来ています。
![Beegoデバッグ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/57bbf1ec-17d1-469d-85a0-adf6e7b12ceb.png)

#### 受け取った画面はこのようになります。
![Beegoデータ取得.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/ce8475af-2606-666b-6044-f6a944d0ee27.png)

# ディレクトリ構造

```
My-First-Beego-Project
├─ conf
│  └─ app.conf
├─ controllers
│  └─ default.go
├─ models
│  └─ todo.go
├─ routers
│  └─ router.go
├─ static
│  ├─ css
│  ├─ img
│  ├─ js
│  │  ├─ form.js
│  │  └─ reload.min.js
│  └─ lib
│     └─ boostrap
│        ├─ css
│        │  ├─ bootstrap-grid.min.css
│        │  └─ bootstrap.min.css
│        ├─ js
│        │  ├─ bootstrap-bundle.min.js
│        │  └─ bootstrap.min.js
│        └─ jquery
│           └─ jquery.js
├─ views
│     ├─ index.tpl
│     ├─ subIndex.tpl
│     └─ thirdIndex.tpl
└─ main.go
```

# フロント画面のコード

```views/thirdIndex.tpl
<!DOCTYPE>
<html>
    <head>
        <title>3つめのページ</title>
        <!--共通ファイル-->
        <link rel="stylesheet" type="text/css" href="/static/lib/bootstrap/css/bootstrap.min.css"/>
        <script type="text/javascript" src="/static/lib/jquery/jquery.js"></script>
        <script type="text/javascript" src="/static/js/form.js"></script>
    </head>
    <body>
        <h2>取得したURLクエリパラメータは：{{.ID}}</h2>
        <form>
            <div class="form-group">
                <label>名前</label>
                <input type="text" id="name" name="name" class="form-control border border-dark" required/>
            </div>
            <div class="form-group">
                <label>E-mail</label>
                <input type="email" id="email" name="email" class="form-control border border-dark" required/>
            </div>
            <div class="form-group">
                <label>パスワード</label>
                <input type="password" id="password" name="password" class="form-control border border-dark" required/>
            </div>
            <div class="mt-4">
                <button type="button" id="submitBtn" class="btn btn-primary">
                    送信
                </button>
            </div>
        </form>

        <div>
        送信したデータ
        <div id="requestedName"></div>
        <div id="requestedEmail"></div>
        <div id="requestedPassword"></div>
        </div>
    </body>
</html>
```

```static/js/form.js
$(document).ready(function(){
    $('#submitBtn').on('click',function(){
        var formData = new FormData();
        formData.append('name',$('#name').val());
        formData.append('email',$('#email').val());
        formData.append('password',$('#password').val());

        $.ajax({
            url:'/controllers/user',
            type:'POST',
            data:formData,
            processData:false,
            contentType:false,
            success:function(response){
                console.log('成功',response);
                //名前のオブジェクトを取得する
                const name = document.getElementById('requestedName');
                name.innerHTML = response.requestData.Name;
                //Emailのオブジェクトを取得する
                const email = document.getElementById('requestedEmail');
                email.innerHTML = response.requestData.Email;
                //パスワードのオブジェクトを取得する
                const password = document.getElementById('requestedPassword');
                password.innerHTML = response.requestData.Password;

            },
            error:function(xhr,status,error){
                console.log('エラー',status,error);
            }
        });
    })
});
```

# サーバサイドのコード

```router/router.go
package routers

import (
	"my-first-beego-project/controllers"
	"github.com/astaxie/beego"
)

func init() {
    beego.Router("/", &controllers.MainController{})
	//追加
	beego.Router("/sub",&controllers.SubController{})
	beego.Router("/:id",&controllers.ThirdController{})
	beego.Router("/controllers/user",&controllers.UserController{})
}
```


```controllers/default.go
package controllers

import (
	"github.com/astaxie/beego"
	"fmt"
)

type MainController struct {
	beego.Controller
}

func (c *MainController) Get() {
	c.Data["Website"] = "beego.me"
	c.Data["Email"] = "astaxie@gmail.com"
	c.TplName = "index.tpl"
}

//20250205追加
type SubController struct {
	beego.Controller
}

type ThirdController struct {
	beego.Controller
}

type UserController struct {
	beego.Controller
}

//20250205
func (c *SubController) Get() {
	c.Data["Page"] = "SubPage"
	c.TplName = "subIndex.tpl"
}

//@router :id[get]
func (this *ThirdController) Get() {
	this.Data["ID"] = this.Ctx.Input.Param(":id")
	this.TplName = "thirdIndex.tpl"
}

func (c *UserController) Post(){
	//フォームデータを取得する
	name := c.GetString("name")
	email := c.GetString("email")
	password := c.GetString("password")

	//デバッグ用
	fmt.Println("フォーム画面から取得したNameは：",name);
	fmt.Println("フォーム画面から取得したEmailは：",email);
	fmt.Println("フォーム画面から取得したPasswordは：",password);

	c.Data["json"] = map[string]interface{}{
		"status":"成功",
		"message":"フォーム画面からデータを受け取りました。",
		"requestData":map[string]string{
			"Name":name,
			"Email":email,
			"Password":password,
		},
	}
	/*
	c.Data["json"] = map[string]string{
		"status":"成功",
		"message":"フォーム画面からデータを受け取りました。",
	}
	*/
	//JSONデータを返却する
	c.ServeJSON()
}
```

:::note warn
<b>[忘れがちなので注意]</b>
今回、サーバから取得したデータをJSON形式で画面に返すが、ケアレスミスをしがちな箇所があります。
それが、<b><font color="red">赤丸</font></b>で囲った<b>カンマ「,」</b>を忘れないようにしよう！

この<b>カンマ「,」</b>が無いと構文エラーを起こしてしまいます。

また、JSONがネストしてる場合は下記のように書きましょう。
具体的には、Goでは map[string]string のような型定義の場合、map の値として他の map や構造体を直接埋め込むことができません。

requestData を map[string]string ではなく、map[string]interface{} にする必要があります。interface{} は任意の型を受け取ることができるので、文字列以外の型（この場合は文字列型の値を持つマップ）を格納できます。


![Beego注意.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1169664/d19e85e7-e24a-5c6c-8204-6228def5da8c.png)

:::

```sample.go
(JSONのネスト無しの場合)

c.Data["json"] = map[string]string{
    "status": "成功",
    "message": "フォーム画面からデータを受け取りました。",
}
//JSONデータを返却する
c.ServeJSON()
```

```sample.go
(JSONネストがある場合)
 // JSONデータを返却する
    c.Data["json"] = map[string]interface{}{
        "status":  "成功",
        "message": "フォーム画面からデータを受け取りました。",
        "requestData": map[string]string{
            "Name":     name,
            "Email":    email,
            "Password": password,
        },
    }
//JSONデータを返却する
c.ServeJSON()
```

以上です。