【ITニュース解説】Submitting a Next.js Form to Google Sheets
2025年10月03日に「Dev.to」が公開したITニュース「Submitting a Next.js Form to Google Sheets」について初心者にもわかりやすく解説しています。
ITニュース概要
Next.jsのフォーム送信データをGoogle Sheetsへ直接保存する方法を解説する。Google Apps Scriptを活用し、無料でサーバーレスにバックエンドなしでデータ収集が可能だ。初心者でも手軽にMVPやランディングページのフォームを実装できる。
ITニュース解説
現代のウェブアプリケーションにおいて、ユーザーからのフィードバックや問い合わせを収集するフォームは欠かせない機能となっている。しかし、簡易的なランディングページや小規模なプロジェクトのために、本格的なサーバーサイド(バックエンド)システムをゼロから構築するのは、時間もコストもかかる重い作業となることが多い。このような状況で、バックエンド開発の知識が少ないシステムエンジニアの卵や、手軽にフォーム機能を実装したい開発者にとって非常に有効な手段が、Googleスプレッドシートを無料かつ信頼性の高いデータベースとして活用する方法である。Next.jsで構築されたフロントエンドのフォームから、直接Googleスプレッドシートにデータを保存するこのアプローチは、サーバーレスで運用でき、初期段階の製品(MVP)やランディングページにおいて高いスケーラビリティを発揮する。
この仕組みを実現するには、まずGoogleスプレッドシートとGoogle Apps Scriptの準備から始める。Googleドライブを開き、新しいスプレッドシートを作成する。このスプレッドシートがフォームから送信されるデータを保存する場所となるため、最初の行には、フォームで収集したい項目に対応するヘッダーを設定する必要がある。具体的には「Name(名前)」「Email(メールアドレス)」「Message(メッセージ)」「Timestamp(送信日時)」といった項目を設定することで、後でデータを確認しやすくなる。スプレッドシートの準備ができたら、次にGoogle Apps ScriptというGoogleが提供するJavaScriptベースのスクリプト環境を使う。スプレッドシートのメニューから「拡張機能」を選び、「App Script」をクリックすると、スクリプトエディタが開かれる。
スクリプトエディタに、フォームからのデータを受け取るためのJavaScriptコードを記述する。このコードの中心となるのがdoPostという特別な関数だ。Google Apps Scriptでは、このdoPost関数が外部からHTTPのPOSTリクエストを受け取ったときに自動的に実行される仕組みになっている。doPost関数はeという引数を受け取るが、このeオブジェクトにはPOSTリクエストに関する様々な情報、特にフォームから送信されたデータが含まれている。コード内ではまず、SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()を使って現在アクティブなスプレッドシートとシート自体を取得している。次に、JSON.parse(e.postData.contents)という部分で、HTTPリクエストのボディに含まれるデータをJSON形式として解析し、JavaScriptが扱えるオブジェクトに変換する。フォームから送信されるデータは通常JSON形式で送られてくるため、この解析処理が必要となる。解析されたデータオブジェクトからは、data.name、data.email、data.messageといった形で個々の情報を取得できる。これらの情報に加えて、new Date()で現在のタイムスタンプ(日時)も取得し、これら全てのデータをsheet.appendRow([...])というメソッドを使って、スプレッドシートの新しい行として追加する。こうすることで、フォームが送信されるたびに、新しいデータがスプレッドシートの下に追加されていく。最後に、ContentService.createTextOutput(JSON.stringify({ status: "success" })).setMimeType(ContentService.MimeType.JSON)という部分では、フォームを送信したクライアント側に対して、処理が成功したことをJSON形式のメッセージ({"status": "success"})として返している。この返答を受け取ることで、クライアント側はフォームの送信が正常に完了したことを確認できる。
このスクリプトは、単に記述しただけでは外部からアクセスできない。ウェブアプリケーションとしてデプロイ(公開)する必要がある。スクリプトエディタのメニューから「デプロイ」を選び、「新しいデプロイ」をクリックする。デプロイの種類として「ウェブアプリ」を選択し、実行者は「自分」、アクセス権は「全員」に設定する。ここで「全員」を選ぶことで、Next.jsのウェブサイトからこのスクリプトにアクセスできるようになる。デプロイが完了すると、一意のWebアプリURLが生成される。このURLは、後でNext.jsのフォームからデータを送信する際のエンドポイントとなるため、大切に控えておく必要がある。
次に、Next.jsアプリケーション側に問い合わせフォームのコンポーネントを実装する。Next.jsはReactというJavaScriptライブラリをベースにしているので、フォームはReactのコンポーネントとして作成する。コンポーネントファイルの先頭に"use client";と記述するのは、このコンポーネントがブラウザ(クライアントサイド)で実行されることをNext.jsに明示するためである。これにより、ユーザーの操作に応じて動的に変化するインタラクティブな要素を扱えるようになる。
フォームの状態管理には、ReactのuseStateフックを用いる。useState({ name: "", email: "", message: "" })で、フォームの入力フィールドに対応する状態を初期化する。これにより、入力された名前、メールアドレス、メッセージをJavaScriptのオブジェクトとして一元的に管理できる。また、フォーム送信中にユーザーが二重に送信ボタンを押さないように、useState(false)でローディング状態も管理する。これは送信ボタンの見た目を変えたり、一時的にボタンを無効化したりするために使われる。
ユーザーが入力フィールドに文字を入力するたびに呼び出されるhandleChange関数は、フォームの入力値をリアルタイムで更新する役割を担う。この関数は、イベントオブジェクトeからどの入力フィールド(e.target.name)が変更されたか、そしてその新しい値(e.target.value)を取得し、setForm({ ...form, [e.target.name]: e.target.value })という形で既存のフォーム状態を保ちつつ、該当するフィールドだけを更新する。これにより、Reactのコンポーネントが常に最新の入力値を反映する「制御コンポーネント」として機能する。
フォームの送信ボタンがクリックされたときに実行されるのがhandleSubmit関数である。この関数は非同期処理(async)として定義されており、ネットワーク通信を伴う処理を待機できる。まず、e.preventDefault()を呼び出すことで、フォームのデフォルトの送信動作(通常はページのリロード)をキャンセルする。これにより、シングルページアプリケーションとしての挙動が維持される。次に、setLoading(true)を設定し、フォームが送信中であることをユーザーに視覚的に伝える。実際のデータ送信は、ブラウザに標準搭載されているfetch APIを使って行われる。await fetch("YOUR_GOOGLE_SCRIPT_URL", { method: "POST", body: JSON.stringify(form) })という部分で、先ほどGoogle Apps Scriptで取得したWebアプリURLに対してHTTP POSTリクエストを送信する。フォームに入力されたデータオブジェクト(form)は、JSON.stringify(form)によってJSON文字列に変換され、リクエストのボディとして送信される。これにより、Apps ScriptのdoPost関数がこのJSONデータを受け取れるようになる。
リクエストが完了すると、res.json()を使ってApps Scriptから返されたJSONレスポンスを解析する。もしレスポンスのstatusが"success"であれば、フォームの送信が成功したことをユーザーにアラートで伝え、setForm({ name: "", email: "", message: "" })でフォームの入力フィールドをクリアする。そうでない場合や、通信中にエラーが発生した場合は、適切なエラーメッセージを表示し、コンソールにエラーの詳細を記録することで、問題の特定に役立てる。try...catchブロックで囲むことで、ネットワーク接続の失敗といった予期せぬエラーにも対応できるようにしている。そして、処理の成功・失敗に関わらず、最終的にfinallyブロックでsetLoading(false)を実行し、ローディング状態を解除して送信ボタンを元の状態に戻す。
コンポーネントの見た目を定義するJSX部分では、inputタグやtextareaタグで入力フィールドを、buttonタグで送信ボタンを作成する。それぞれの入力フィールドには、name属性とvalue属性、そしてonChangeハンドラーを設定することで、Reactの状態で管理される制御コンポーネントとする。送信ボタンには、disabled={loading}を設定し、loading状態がtrueの間はボタンが無効化されるようにする。また、表示されるテキストもloading状態に応じて「Submitting...」と「Submit」で切り替わるようにすることで、ユーザー体験を向上させる。
全てのコードが実装できたら、Next.jsプロジェクトをローカル環境で実行するか、Vercelなどのプラットフォームにデプロイする。実際にブラウザでフォームにデータを入力し、送信ボタンをクリックしてみる。数秒後、Googleスプレッドシートを開いて新しい行が追加され、フォームから入力されたデータが正確に記録されていることを確認できれば、統合は成功である。この方法の最大のメリットは、本格的なバックエンドサーバーを構築・管理する手間とコストをかけずに、短時間で堅牢なフォームデータ収集システムを構築できる点にある。さらに、プロジェクトが成長し、より複雑なデータ管理が必要になった際には、GoogleスプレッドシートからNode.jsとExpress、MongoDBのような本格的なバックエンドシステムへの移行も比較的容易に行えるため、初期段階のプロジェクトにおいては非常に有効で実用的なアプローチと言える。システムエンジニアを目指す初心者にとって、このような既存サービスを組み合わせて新しい価値を生み出す手法を学ぶことは、実践的なスキルとして非常に価値が高い。