11
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Fetch APIでGoogle Formsに非同期でデータを送信する方法

Last updated at Posted at 2022-03-12

はじめに

この記事では、Google FormsをカスタムUIで利用し、ページ遷移なしでフォームの回答を送信する方法を解説します。

この記事が解決する課題

通常、HTMLの<form>タグでGoogle Formsにデータを送信すると、送信後にGoogleの確認ページに遷移してしまいます。
これを避けて、ユーザー体験を損なわずに自作のページ内で非同期にデータを送信したい、という課題を解決します。

ターゲット読者

  • 独自のフロントエンドデザインでGoogle Formsを利用したい方
  • JavaScriptのFetch APIを使ってフォームデータを非同期送信したい方

記事のゴール

この記事を読み終えることで、Fetch APIを用いてGoogle FormsにデータをPOSTし、ページ遷移を防ぐ実装方法を理解できます。


前提条件

この記事は、Google Formsの基本的な作成方法を理解していることを前提としています。

実装手順

実装は大きく分けて2つのステップで行います。

  1. Google Formsから送信先URLとエントリーIDを取得する
  2. Fetch APIを使ってデータをPOSTする

1. 送信先URLとエントリーIDの取得

まず、送信先となるURLと、各フォーム項目に対応するID(エントリーID)を特定します。

  1. 作成したGoogle Formのプレビュー画面を開きます。
  2. ブラウザの検証ツール(デベロッパーツール)を開き、Networkタブを表示した状態で、すべての項目にテストデータを入力して送信します。
  3. 送信後、Networkタブのリストから formResponse という名前のリクエストを探します。
  4. formResponseHeaders タブで、Request URL を確認します。これがデータをPOSTする先のURLです。
  5. 次に Payload (または Request ) タブで、送信されたデータを確認します。entry.xxxx のようなキーと、入力したテストデータが値として表示されています。この entry.xxxx が各項目に対応するエントリーIDです。

検証ツールでformResponseを確認する
ブラウザの検証ツールでformResponseを確認し、リクエストURLとエントリーIDを控えておきます。

2. Fetch APIでデータをPOSTする

取得したURLとエントリーIDを使って、Fetch APIでデータを送信するJavaScriptコードを記述します。

HTMLの例

まず、データを入力するためのHTMLフォームを用意します。action属性は不要です。

<form id="custom-form">
  <input type="text" name="question1" placeholder="質問1の回答">
  <input type="text" name="question2" placeholder="質問2の回答">
  <textarea name="question3" placeholder="質問3の回答"></textarea>
  <button type="submit">送信</button>
</form>

JavaScriptの例

次に、フォームの送信イベントを捕捉し、Fetch APIでデータをPOSTする処理を実装します。

document.getElementById('custom-form').addEventListener('submit', (e) => {
  // デフォルトのフォーム送信をキャンセル
  e.preventDefault();

  // Google FormのURLとエントリーID
  const GOOGLE_FORM_URL = 'https://docs.google.com/forms/d/e/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/formResponse';
  const ENTRY_IDS = {
    question1: 'entry.xxxx',
    question2: 'entry.yyyy',
    question3: 'entry.zzzz',
  };

  // フォームデータを取得
  const formData = new FormData(e.target);
  const formEntries = Object.fromEntries(formData.entries());

  // POSTするデータを作成 (URLエンコード)
  const body = new URLSearchParams();
  body.append(ENTRY_IDS.question1, formEntries.question1);
  body.append(ENTRY_IDS.question2, formEntries.question2);
  body.append(ENTRY_IDS.question3, formEntries.question3);

  // Fetch APIでデータを送信
  fetch(GOOGLE_FORM_URL, {
    method: 'POST',
    mode: 'no-cors', // CORSエラーを回避するために必要
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: body.toString(),
  })
  .then(() => {
    console.log('フォームが正常に送信されました。');
    // ここでサンクスページの表示などの処理を行う
  })
  .catch((error) => {
    console.error('送信中にエラーが発生しました:', error);
    // エラー処理
  });
});

コードのポイント

  • mode: 'no-cors': Google Formsのエンドポイントは外部ドメインからのリクエストを想定していないため、CORSポリシー違反のエラーが発生します。mode: 'no-cors' を指定することで、レスポンスの内容にはアクセスできなくなりますが、リクエストを送信すること自体は可能になります。
  • Content-Type: application/x-www-form-urlencoded を指定します。
  • URLSearchParams: URLSearchParams オブジェクトを利用すると、キーと値をURLエンコードされたクエリ文字列 (key1=value1&key2=value2) に簡単に変換できます。

注意点

  • バリデーション: この方法では、Google Forms側で設定した「必須項目」などのバリデーションが機能しません。そのため、フロントエンド側で独自のバリデーションを実装する必要があります。
  • エラーハンドリング: no-cors モードでは、サーバーからのレスポンスコード(成功か失敗か)を受け取ることができません。送信が成功したかどうかの確実な判定は難しいため、ユーザーには「送信されました」と楽観的なUIを見せつつ、重要なフォームでは別の方法を検討する方が良いかもしれません。
  • JavaScriptへの依存: この方法はJavaScriptが有効な環境でしか動作しません。

まとめ

Fetch APIと no-cors モードを利用することで、ページ遷移なしでGoogle Formsにデータを送信できます。これにより、サーバーレスで無料のフォームバックエンドとしてGoogle Formsを活用しつつ、UI/UXを自由にカスタマイズすることが可能になります。

ただし、CORSの制約によるエラーハンドリングの難しさなどのデメリットも理解した上で利用することが重要です。

参考資料

11
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?