24日目にLINEミニアプリが完成する初心者 ── Day8. スプレッドシートとの連携


# はじめに

前回は「24 日目に LINE ミニアプリが完成する初心者 ── Day7. フォーム UI の作成」と題して、資料請求フォームの UI を作成しました。

https://qiita.com/non_watanabe/private/31705724fc969e87c8db

<br/>
今回は、GASを使ってフォームで入力されたデータをGoogleスプレッドシートに保存する機能を実装していきたいと思います。

# GAS（Google Apps Script）の設定

はじめに GAS ってなに？という人のために簡単に説明を載せておきます。

https://workspace.google.com/intl/ja/products/apps-script/

<br/>
GAS（Google Apps Script）は、Google スプレッドシートや Google ドキュメントなどの Google 製品を操作するための JavaScript ベースのローコードプラットフォームです。

基本的な説明は省くため、初めて使うよって方は以下の記事で 1 から説明していますので参考にしてみてください。

https://goodlocal.jp/blog/ku4KuCXf

## スプレッドシートの作成

まず、フォームのデータを保存するためのスプレッドシートを新規で作成しましょう。

今回私は「LINE 資料請求」という名前でスプレッドシートを作成しました。

以下のヘッダーには以下を設定します。

- **A1: お名前**
- **B1: メールアドレス**
- **C1: 電話番号**
- **D1: 郵便番号**
- **E1: 都道府県**
- **F1: 市区町村**
- **G1: 町名・番地**
- **H1: メッセージ**
- **I1: 送信日時**

<br/>
こんな感じで作成ができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2743174/4e6dca9e-d588-b243-9853-d690fe6bcb79.png)

## Google Apps Script の作成

次に GAS のプロジェクトを作成します。

スプレッドシート上部のメニューから「拡張機能」>「Apps Script」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2743174/1840885b-f993-0a7a-2299-d754d37e6ab9.png)

<br/>
プロジェクト名もスプレッドシートに合わせて「「LINE 資料請求」としました。

では早速コードを書いていきます。

```js
function doPost(e) {
  try {
    // JSONをパース
    const data = JSON.parse(e.postData.contents);

    // スプレッドシートを取得
    const sheet = SpreadsheetApp.getActiveSheet();

    // データを行として追加
    sheet.appendRow([
      data.name,
      data.email,
      data.tel,
      data.postalCode,
      data.prefecture,
      data.city,
      data.address,
      data.message,
      new Date().toLocaleString(), // 現在時刻
    ]);

    return ContentService.createTextOutput(
      JSON.stringify({ success: true, message: "Data added successfully" })
    ).setMimeType(ContentService.MimeType.JSON);
  } catch (error) {
    console.log("Error: " + error.message);
    return ContentService.createTextOutput(
      JSON.stringify({ success: false, error: error.message })
    ).setMimeType(ContentService.MimeType.JSON);
  }
}
```

データを受け取って`appendRow`でスプレッドシートに追加するというシンプルな処理です。

## GAS のデプロイ

Next.js からデータを受け取るためには GAS のデプロイが必要になります。

右上の「デプロイ」ボタンから「新しいデプロイ」をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2743174/7e1ab866-9abb-c194-3697-2767bd589c7f.png)

<br/>
種類の選択がありますが、ここでは「ウェブアプリ」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2743174/9b8b5c2d-83a3-27e3-f1ee-92a9471c8d6f.png)

<br/>
ここでデプロイの情報を設定します。

- **新しい説明文：** 資料請求フォーム（API わかりやすいものであれば構いません）
- **次のユーザーとして実行：** 自分
- **アクセスできるユーザー：** 全員

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2743174/435551eb-348f-c665-6e56-384942f18ae6.png)

最後に右下の「デプロイ」ボタンをクリックしたらデプロイは完了です。
<br/>

:::note warn
**初回のデプロイ時 Google アカウントの認証が求められることがあります。**

その場合は画面の指示に従って認証を完了させてください。
:::

<br/>
デプロイが完了すると最後にデプロイ ID とウェブアプリの URL が表示されます。

この URL については、後ほど Next.js で使用するのでコピーしておいてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2743174/3e3ab185-ccc5-de0e-9d56-d1972e8e12ae.png)

# フォームの送信処理の実装

GAS の準備が完了したら、Next.js でフォームの送信処理を実装していきます。

## 環境変数の設定

はじめに`src/nextjs`配下に`.env.local`ファイルを作成し、先ほどコピーした Google Apps Script の URL を設定しておきましょう。

```
NEXT_PUBLIC_GOOGLE_SCRIPT_URL=your-script-url
```

## API 関数の作成

次に Google Apps Script にデータを送信するための API 関数を、Next.js の API ルートを使って作成します。

この関数は、クライアントからの POST リクエストを受け取り、Google Apps Script の URL にデータを転送します。

```ts:src/pages/api/catalog.ts
import type { NextApiRequest, NextApiResponse } from "next";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const { method, body } = req;
  if (method === "POST") {
    try {
      const scriptUrl = process.env.NEXT_PUBLIC_GOOGLE_SCRIPT_URL;

      const response = await fetch(scriptUrl, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body,
      });

      const result = await response.json();
      res.status(200).json(result);
    } catch (err) {
      res.status(500).json({ error: "Internal Server Error" });
    }
  } else {
    res.setHeader("Allow", ["POST"]);
    res.status(405).end(`Method ${req.method} Not Allowed`);
  }
}
```

## フォームの送信処理の実装

フォームの送信処理は今回、 SWR というライブラリを使ってを実装したいと思います。

https://swr.vercel.app/ja

TanStack Queryよりシンプルな記述で書けるので、今回はこちらを採用しました。

### SWR のインストール

`src/nextjs`配下で以下のコマンドを実行しましょう。

```bash
npm install swr
```

### フォームの送信処理の実装

送信処理には`useSWRMutation`を使用するため、先にフェッチャー関数を定義します。

```tsx:src/nextjs/components/pages/catalog/CatalogPage.tsx
import useSWRMutation from "swr/mutation";

// （中略）

async function sendData<T>(url: string, { arg }: { arg: T }) {
  await fetch(url, {
    method: "POST",
    body: JSON.stringify(arg),
  });
}
```

このフェッチャー関数と path を`useSWRMutation`に渡して、`trigger`関数を取得します。

今回は送信ボタンを押した際に送信処理を実行するため、`onSubmit`関数内で`trigger`関数を呼び出します。

```tsx:src/nextjs/components/pages/catalog/CatalogPage.tsx
import { useForm, SubmitHandler } from "react-hook-form";
import useSWRMutation from "swr/mutation";

// （中略）

async function updateUser(url: string, { arg }: { arg: CatalogPageProps }) {
  await fetch(url, {
    method: "POST",
    body: JSON.stringify(arg),
  });
}

export default function CatalogPage() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<CatalogPageProps>();

  const { trigger: catalogTrigger, isMutating } = useSWRMutation(
    "/api/catalog",
    sendData<CatalogPageProps>
  );
  
  const onSubmit: SubmitHandler<CatalogPageProps> = (data) => {
    console.log(data);
    trigger(data);
  };

  // （中略）
}
```

これで送信処理の実装は完了です！

# 動作確認

それでは動作確認をしていきましょう。

<br/>
ブラウザの検証ツールからネットワークを開いた後、フォームにテストデータを入力して送信ボタンをクリックしてみます。

200 のステータスコードが確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2743174/272f6d8e-58ce-5d11-0430-ffc07a802302.png)

<br/>
GASの実行数のタブも見てみましょう。

筆者は何度も試したためバージョン 7 の表記になっていますが、ステータスは完了で表示されているのがわかると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2743174/f9c8835f-be27-2d77-79d1-93dcb8882dfb.png)

<br/>
最後にスプレッドシートを見てみます。

フォームで入力した内容が出力されているのが確認できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2743174/a7ab3b63-1a16-2863-e5f8-cc622419cf8d.png)

# Netlify への環境変数設定

最後に`.env.local`に設定した環境変数を Netlify にも設定しておきましょう。

```terminal
$ netlify env:set NEXT_PUBLIC_GOOGLE_SCRIPT_URL "your-script-url"
```

# まとめ

今回は GAS を使用してフォームデータをスプレッドシートに保存する機能を実装しました。

次回は、送信完了時の完了画面等を作成し資料請求フォーム UI を完成させていきます。

残りは 16 日！
気になる方は是非フォローやカレンダー購読をお願いします:star: