0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

honoはじめ

Last updated at Posted at 2025-01-06

はじめに

シゴトでdevcontainerを使ってNextJSを動かすととても重くて、最近はフロントをhostで開発している。そもそもdevcontainerで快適なぐらいのないの?ってのでたどり着いたフレームワーク。FastAPIのようなノリで使えそう。まぁでもこの記事ではdockerは使わない。あくまでhonoの記事。

このIssueで使うかー

プロジェクトの作成

日本製!

console
cd C:\Users\yoshi\OneDrive\dev
npm create hono@latest
  Need to install the following packages:
    create-hono@0.14.3
  Ok to proceed? (y) y
  create-hono version 0.14.3
  ? Target directory hono_playground
  ? Which template do you want to use? nodejs
  ? Do you want to install project dependencies? yes
  ? Which package manager do you want to use? npm
  ✔ Cloning the template
  ✔ Installing project dependencies
  🎉 Copied project files
  Get started with: cd hono_playground
  npm notice 
  npm notice New major version of npm available! 9.6.7 -> 11.0.0
  npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.0.0
  npm notice Run npm install -g npm@11.0.0 to update!
  npm notice

code .\hono_playground\
npm run dev

image.png

tsconfig

  • なんだかhonoの標準のgenerateが古いらしい... importの仕方とかが慣れないかたちになるのでtsconfigをいじる
{
  "compilerOptions": {
    "target": "ESNext",
-   "module": "NodeNext",
+   "module": "ESNext",
+   "moduleResolution": "bundler",
    "strict": true,
    "verbatimModuleSyntax": true,
    "skipLibCheck": true,
    "types": [
      "node"
    ],
    "jsx": "react-jsx",
    "jsxImportSource": "hono/jsx",
  }
}

テキストフォームを使ってPOST送信

  • json でPOSTする
  • c.req.json() で受ける
  • json で返す
  • result を受けてHTMLを書き換える

ついでにこれのエッセンスもいれちゃおう
HTMLのinputの配列は添字に key が指定できる

{
  "use[1]": "on",
  "name_short[1]": "資格A",
  "name_long[1]": "資格A 長い名前",
  "address[1]": "住所A",
  "use[2]": "on",
  "name_short[2]": "資格B",
  "name_long[2]": "資格B 長い名前",
  "address[2]": "住所B"
}
src\index.ts
import { serve } from "@hono/node-server";
import { Hono } from "hono";

const app = new Hono();

app.get("/", (c) => {
  return c.html(`
    <html>
      <head>
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet">
      </head>
      <body>
        <div class="container mt-5">
          <h1>フォーム送信デモ</h1>
          <form id="demoForm" class="mt-4">
            <div class="mb-3">
              <label for="name" class="form-label">名前</label>
              <input type="text" class="form-control" id="name" name="name" required>
            </div>
            <div class="mb-3">
              <label for="message" class="form-label">メッセージ</label>
              <textarea class="form-control" id="message" name="message" rows="3" required></textarea>
            </div>

            <h3 class="mt-4">資格リスト</h3>
            <table class="table">
              <thead>
                <tr>
                  <th>使う</th>
                  <th>資格名</th>
                  <th>資格名(長い名前)</th>
                  <th>住所</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td><input type="checkbox" name="use[1]" checked></td>
                  <td><input type="text" name="name_short[1]" value="資格A" class="form-control"></td>
                  <td><input type="text" name="name_long[1]" value="資格A 長い名前" class="form-control"></td>
                  <td><input type="text" name="address[1]" value="住所A" class="form-control"></td>
                </tr>
                <tr>
                  <td><input type="checkbox" name="use[2]"></td>
                  <td><input type="text" name="name_short[2]" value="資格B" class="form-control"></td>
                  <td><input type="text" name="name_long[2]" value="資格B 長い名前" class="form-control"></td>
                  <td><input type="text" name="address[2]" value="住所B" class="form-control"></td>
                </tr>
              </tbody>
            </table>

            <button type="submit" class="btn btn-primary">送信</button>
          </form>
          <div id="responseMessage" class="mt-3"></div>
        </div>
        <script>
          const form = document.getElementById('demoForm')
          const responseMessage = document.getElementById('responseMessage')

          form.addEventListener('submit', async (event) => {
            event.preventDefault()
            const formData = new FormData(form)
            const data = Object.fromEntries(formData)
            const response = await fetch('/submit', {
              method: 'POST',
              headers: {'Content-Type': 'application/json'},
              body: JSON.stringify(data)
            })

            const result = await response.json()
            
            responseMessage.innerHTML = \`<div class="alert alert-success">サーバーからの応答: \${result.message}<br>\${JSON.stringify(result.certifications, null, 2)}</div>\`
          })
        </script>
      </body>
    </html>
  `);
});

app.post("/submit", async (c) => {
  const body = await c.req.json();
  console.log(body);

  const { name, message } = body;

  // 配列データを再構築
  const certifications: Array<{
    id: string;
    name_short: string;
    name_long: string;
    address: string;
    used: boolean;
  }> = [];

  for (const key in body) {
    if (key.startsWith("use[")) {
      const id = key.match(/\[(\d+)\]/)?.[1]; // `use[1]` -> `1`
      if (id) {
        certifications.push({
          id,
          name_short: body[`name_short[${id}]`] || "", // 対応する name_short を取得
          name_long: body[`name_long[${id}]`] || "", // 対応する name_long を取得
          address: body[`address[${id}]`] || "", // 対応する address を取得
          used: body[key] === "on", // チェックボックスが選択されている場合
        });
      }
    }
  }

  return c.json({
    message: `こんにちは、${name}!メッセージ「${message}」を受け取りました。`,
    certifications,
  });
});

const port = 3000;
console.log(`Server is running on http://localhost:${port}`);

serve({
  fetch: app.fetch,
  port,
});

image.png
image.png

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?