フォーム ID

Gatsby

ハイドレーション前から静的な HTML で動き、その後は fetch で拡張される Gatsby のフォームと、シークレットキーで送信する Gatsby Function。

Gatsby はビルド時にすべてのページを HTML に描画します。フォームに本物の action を付ければ、React がハイドレーションする前や、バンドルの読み込みに失敗した場合でも送信できます。ハイドレーション後は、コンポーネントが fetch で送信し、結果をその場に表示します。

ブラウザーから送信する

  1. フォーム ID を追加する

    .env.production
    GATSBY_IKIFORM_FORM_ID=frm_xxxxxxxxxxxxxxxx

    Gatsby がブラウザーのコードに公開するのは GATSBY_ で始まる変数だけで、ビルド時に埋め込まれます。gatsby develop 用に、同じ行を .env.development にも追加してください。

  2. コンポーネントを追加する

    src/components/contact-form.js
    import * as React from "react";
    
    const endpoint = `https://ikiform.com/f/${process.env.GATSBY_IKIFORM_FORM_ID}`;
    
    export default function ContactForm() {
      const [status, setStatus] = React.useState("idle");
      const [message, setMessage] = React.useState("");
    
      async function onSubmit(event) {
        event.preventDefault();
        setStatus("sending");
        try {
          const response = await fetch(endpoint, {
            method: "POST",
            headers: { Accept: "application/json" },
            body: new FormData(event.currentTarget),
          });
          const result = await response.json();
          if (result.ok) return setStatus("sent");
          setMessage(result.error.message);
        } catch {
          setMessage("Couldn't reach the server. Try again.");
        }
        setStatus("error");
      }
    
      if (status === "sent") return <p>Thanks, we got it.</p>;
    
      return (
        <form action={endpoint} method="post" onSubmit={onSubmit}>
          <label>
            Email
            <input name="email" type="email" autoComplete="email" required />
          </label>
          <label>
            Message
            <textarea name="message" rows={5} />
          </label>
          <input type="hidden" name="_redirect" value="https://example.com/thanks/" />
          <input name="_gotcha" type="text" tabIndex={-1} autoComplete="off" hidden />
          {status === "error" ? <p role="alert">{message}</p> : null}
          <button disabled={status === "sending"}>Send</button>
        </form>
      );
    }

    src/pages/contact.js など任意のページから描画し、JavaScript なしの場合のリダイレクト用に src/pages/thanks.js を追加します。フィールドエラーや SDK の人間確認を使うには、React のガイドのように拡張してください。

Gatsby Function から送信する

Gatsby Function はシークレットキーを付けて送信を転送できるので、許可ドメインと人間確認をスキップできます。動くのは、Gatsby のアダプターを使った Netlify など、Gatsby Functions に対応したホストだけです。GitHub Pages のような完全な静的ホストでは動きません。IKIFORM_FORM_ID と、submissions:write スコープを持つシークレットキーを IKIFORM_SECRET_KEY として保存します。ブラウザーに届かないよう、GATSBY_ は付けないでください。

src/api/contact.js
export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).end();
  const response = await fetch(`https://ikiform.com/f/${process.env.IKIFORM_FORM_ID}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      Authorization: `Bearer ${process.env.IKIFORM_SECRET_KEY}`,
    },
    body: JSON.stringify(req.body),
  });
  res.status(response.status).json(await response.json());
}

Gatsby は JSON とフォームエンコードのボディを req.body に解析するので、ページからはどちらの形式でも /api/contact に送信できます。その場合、すべての送信がレート制限上は Function の IP アドレスを共有します。サーバーから送信するを参照してください。

許可ドメイン

これはブラウザーからの送信に当てはまります。Gatsby Function からの送信はシークレットキーを使うので、チェックをスキップします。

フォームが動く場所許可ドメインに追加するもの
gatsby develop と gatsby servelocalhost。http://localhost:8000 と http://localhost:9000 に一致します。Ikiform が比較するのはホスト名だけで、ポートは比較しません。
自分のドメインexample.com(www.example.com も含まれます)
Netlifyyour-site.netlify.app。デプロイプレビュー(deploy-preview-12--your-site.netlify.app)やブランチデプロイ(branch--your-site.netlify.app)はそのサブドメインではないので、テストする間はプレビューの正確なホストを追加してください。
Cloudflare Pagesyour-project.pages.dev。abc123.your-project.pages.dev のようなプレビュー URL はそのサブドメインなので、すでに一致します。
  • netlify.app や pages.dev だけを追加しないでください。他の人のサイトも含め、そのホスト上のすべてのサイトが一致してしまいます。

テストのチェックリスト

  1. gatsby build を実行し、public/contact/index.html を開きます。フォームの action が undefined ではなく、フォーム ID で終わっているはずです。
  2. 許可ドメインに localhost を入れて gatsby serve を実行し、送信します。お礼のメッセージがフォームに置き換わるはずです。
  3. JavaScript をオフにし、再読み込みして送信します。ローカルでは Ikiform のサンクスページが、https: のドメインでは /thanks/ が表示されるはずです。
  4. Function を使う場合は、デプロイプレビューで /api/contact に送信し、送信データが Ikiform に表示されることを確認します。

トラブルシューティング

症状原因対処
404 not_found になり、action が /f/undefined で終わっている変数に GATSBY_ が付いていない、またはビルド時に設定されていなかったGATSBY_IKIFORM_FORM_ID という名前にして、再ビルドします。
Function が 403 forbidden を返すシークレットキーが別のワークスペースのもの、無効化されている、または submissions:write がないそのスコープを持つシークレットキーを作成します。
デプロイ後に /api/contact が 404 を返すホスティング先が静的ファイルしか配信しないGatsby Functions に対応したホストにデプロイするか、ブラウザー版を使います。
送信データが origin_mismatch でスパムフィルターの下に届く送信したページが、フォームの許可ドメインに含まれていない上の表のホストを追加します。Reject を選んでいる場合、同じ送信には代わりに 403 origin_not_allowed が返ります。