フロントNextjsで入力した文字をGinで受け取りRedisに登録

# やりたいこと
フロント側で入力した文字をバックエンドに送信して、データベースに登録する

## 環境構築

https://qiita.com/zukka/items/5a6831bef702d8c910e0

https://qiita.com/zukka/items/f019b7a384feaf03c65a


## フロントエンド
フォルダ・ファイル作成
個別用にlayoutファイルとCSSモジュールを作成

```
react/src/
┣ app
┃  ┗　input-text
┃   ┣ page.tsx
┃　　　　　　┣ layout.tsx
┃　　　　　　
┗　components
　　　　┗　ui-elements
    ┗　input-test.module.css

```
### page.tsx
ページ表示部分

```react
"use client";

import axios from "axios";
import { useState } from "react";

// CSS Modulesの読み込み
import styles from '../../components/ui-elements/input-test.module.css'


export default function Page() {
    const [input_data, setMessage] = useState('wait');

    async function action_test(form) {
        try {
            // フォーム入力データの取得
            const input_data = form.get('input_data')
            // Go APIのURL
            const url = "http://localhost:3001/input";
            // PostData
            const data = {
                InputData: input_data,
            };
            // API送信
            const response = await axios.post(url, data);
            console.log(response.data);
            setMessage(response.data['input_data']);
        } catch (error) {
            console.error('Error fetching data:', error);
        }
    }

  return (
    <>
      <h1>送信テスト</h1>
      <form action={action_test}>
        <input className={styles.inputbox} type="text" name="input_data" />
        <button className={styles.sendbtn} type="submit">送信</button>
      </form>
      <p>入力した文字は：{message}</p>
    </>
  )
}

```

### layout.tsx
今回は共通レイアウトではなく個別にレイアウトを設定したいため、layoutファイルを作成

```react
export default function Layout({
    children,
}: {
    children: React.ReactNode
}) {
    return (
        <>
            <hr />
            <div>{children}</div>
            <hr />
            <p>個別レイアウト</p>
        </>
    )
}
```

### input-test.module.css
今回は、モジュールとしてcssを読み込むことにする

:::note warn
※モジュールとして読み込み場合、拡張子は.module.cssとする必要がある
:::

```css
.inputbox{
    color:black;
    padding: 10px;
    margin:20px;
    border-radius: 10px;
}

.sendbtn{
    color:black;
    background-color: #A9A9A9;
    padding:10px 20px;
    border-radius: 10px;
}
```


## バックエンド

### main.go
ルーティングを追加。

```go
r.POST("/input", controller.RedisInput)
```

### controller.go
受信する構造体の定義と受信時の処理を追加

```go
// 構造体InputStringにstring型のInputDataを宣言
type InputString struct{
	InputData string
}

func RedisInput(context *gin.Context) {
	rdb := service.Init()
	fmt.Printf("%T\n", rdb)

    // 構造体InputStringを変数hogeで宣言
	var hoge InputString
    // request bodyを変数hogeにバインド
	context.BindJSON(&hoge)

    // この処理で扱うkeyに"InputData"を設定
	key := "InputData"
    // 変数valueに受信したInputDataを代入
	value := hoge.InputData
	
	// SETコマンドでkey-valueペアを設定
	err := rdb.Set(key, value, 0).Err()
	if err != nil {
		log.Fatalf("Failed to set key: %v", err)
	}

	fmt.Printf("%s\n", "get")
	// GETコマンドでkeyのvalueを取得
	val, err := rdb.Get(key).Result()
	if err != nil {
		log.Fatalf("Failed to get key: %v", err)
	}
	fmt.Println("key:", val)

	context.JSON(http.StatusOK, gin.H{
		"message": val,
	})
}
```

## 動作確認

### 実行前
![スクリーンショット 2024-02-29 11.55.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17764/00b0c8eb-9f21-81ef-1f40-6a4c88928c13.png)


### 文字入力後、送信実行
![スクリーンショット 2024-02-29 11.55.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17764/9a50417c-a902-dd33-355b-bf8abf42f6a2.png)

入力した文字が返ってきたので、下部に入力した文字と同じ文字が表示されている

### phpRedisAdminで確認

![スクリーンショット 2024-02-29 11.55.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17764/23e8aa36-390e-1a23-20b4-18b87f4739d0.png)

入力した文字が保存されている。