Cloudflare Workers で Form の結果を表示する

2024/01/14に公開

はじめに

ここでは、Formで送信した結果に対して処理を行い、結果を表示することを行う。
りんごの購入数とみかんの購入数を入力し、購入するボタンをクリックすると、結果が表示される。


リクエスト送信前


リクエスト送信後

1. プロジェクトを作成する

  1. サインアップする。
  2. プロジェクトを作成する。
  • プロジェクト名: my-app
  • TypeScriptを選択
npm create cloudflare@latest -- my-app
What type of application do you want to create?
> "Hello World" Worker

Do you want to use TypeScript?
> Yes

Do you want to use git for version control?
> No

Do you want to deploy your application?
> Yes
  1. デプロイが完了後、deployment is ready at:の後に URL が表示され、ブラウザが開く。
  2. ログイン後、左タブのWorkers & Pagesで確認できる。

2. フォームの作成

ここでは、Node.jsで簡易的なフォーム画面を作成する。
リクエストを送信に関しては、次のステップ3を参考にする。

  1. プロジェクトのディレクトリ作成
mkdir my-app-front
cd my-app-front
  1. package.jsonファイルの初期化
npm init
  1. ファイルの作成
    JSファイルのurlには、1で生成されたURLを記入する。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>My Project</title>
  <link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
  <main>
    <form id="form">
      <div>
        <label>りんご(200円): </label>
        <input type="number" name="apple" id="apple" />
      </div>
      <div>
        <label>みかん(300円): </label>
        <input type="number" name="orange" id="orange" />
      </div>
      <input type="submit" value="購入する" />
    </form>

    <ul id="form-result">
      <p>注文結果:</p>
      <p>注文番号:</p>
      <p id="order-number"></p>
      <p>合計金額:</p>
      <li id="total-amount"></li>
    </ul>
  </main>
  <script src="app.js"></script>
</body>
</html>

style.css

* {
  margin: 0;
  padding: 0;
}

main {
  padding: 100px 0 0 100px;
}

form {
  margin-bottom: 40px;
}

ul {
  list-style: none;
  padding-left: 0;
}

app.js

document.getElementById("form").addEventListener("submit", function (e) {
e.preventDefault();

const formData = new FormData(e.target);
const url = 1で生成されたURL;

fetch(url, {
  method: "POST",
  mode: "cors",
  headers: {
    "Content-Type": "application/json",
  },
  body: JSON.stringify(Object.fromEntries(formData.entries())),
})
  .then((response) => response.json())
  .then((data) => {
    const orderNumber = document.getElementById("order-number");
    const totalAmount = document.getElementById("total-amount");
    orderNumber.textContent = data["order-number"];
    totalAmount.textContent = data["total-amount"] + "円";
  })
  .catch((error) => {
    console.error("リクエストエラー", error);
  });
});

  1. ローカルサーバーの起動
    ここでは、http-serverをインストールして起動する。
    ブラウザで http://localhost:8080 にアクセスすると、作成したページを確認できる。
npm install -g http-server
http-server

3. 処理を変更してリデプロイ

ここでは、リクエストを受け取った後、合計金額を計算&注文番号を生成する処理を行い、レスポンスを返す。コードは、1で作成したmy-appディレクトリ内のsrc/index.tsを編集する。

データ設定(リクエスト)

JSON Key 必須 値の説明
apple Int りんごの購入数
orange Int みかんの購入数

データ設定(レスポンス)

JSON Key 必須 値の説明
order-number Int 注文番号。RANDOM_MINからRANDOM_MAXの間のランダムな整数
total-amount Int APPLE_AMOUTORANGE_AMOUTをもとにした合計金額
...
interface FormData {
  apple: number;
  orange: number;
}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    try {
      if (request.method === 'POST') {
	const APPLE_AMOUT = 200;
	const ORANGE_AMOUT = 300;
	const RANDOM_MAX = 10000;
	const RANDOM_MIN = 1;

	const formData: FormData = await request.json();
	const orderNumber = Math.floor(Math.random() * (RANDOM_MAX + 1 - RANDOM_MIN)) + RANDOM_MIN;
	const totalAmount = formData['apple'] * APPLE_AMOUT + formData['orange'] * ORANGE_AMOUT;

	const responseData = {
	  'order-number': orderNumber,
	  'total-amount': totalAmount,
	};
	const response = new Response(JSON.stringify(responseData));

	response.headers.set('Content-Type', 'application/json');
	response.headers.set('Access-Control-Allow-Origin', '*');
	response.headers.set('Access-Control-Allow-Headers', 'X-Requested-With, Origin, X-Csrftoken, Content-Type, Accept');

        return response;
      } else if (
	// プリフライトリクエストに対してOKステータスを返す
	request.method === 'OPTIONS'
      ) {
        return new Response(null, {
	    status: 200,
	    headers: {
		'Access-Control-Allow-Origin': '*',
		'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
		'Access-Control-Allow-Headers': 'Content-Type',
	    },
	});
	} else {
	return new Response('Method Not Allowed', {
	    headers: {
	      'Content-Type': 'application/json',
	      'Access-Control-Allow-Origin': '*',
	      'Access-Control-Allow-Headers': 'X-Requested-With, Origin, X-Csrftoken, Content-Type, Accept',
	    },
	    status: 405,
	    statusText: 'Method Not Allowed',
	});
	}
} catch (error) {
  console.error('Error processing form data:', error);
  return new Response('Internal Server Error', {
    status: 500,
    statusText: 'Internal Server Error',
   });
   }
  },
};

編集後、以下のコマンドでデプロイする。

npx wrangler deploy

参考

https://workers.cloudflare.com/

https://zenn.dev/moutend/articles/97c98a277f4bae

https://qiita.com/laughingman/items/4ff20268fa34dc9e1be3

Discussion