Honoxで、サーバーサイドとクライアントサイドのfetchを試してみた

HonoでWebサイトを作る「honox」の実装方法を紹介。クライアント・サーバーサイドでのデータ取得やAPI呼び出しを説明。外部APIを用意し、クライアントでfetchやサーバーでfetch、レスポンス表示する手順を示す。Reactライクな使い勝手とHono/Cloudflare Workersっぽい特徴がある。honoxは個人的に興味深く、SSGの場合はAstroを、サーバー側処理が多い場合はhonoxを推奨。

広告ここから
広告ここまで

目次

    HonoでWebサイトを作れる「honox」が登場しました。サイト構築となると、外部のAPIからデータを取得する処理を書くことが少なくないですが、honoxでクライアントサイド・サーバーサイドそれぞれどのように実装することになるかを試してみた覚書です。

    プロジェクトのセットアップ

    テストに使うプロジェクトを、create-honoで作りましょう。

    % npm create hono
    Need to install the following packages:
      [email protected]
    Ok to proceed? (y) 

    honoxを使うには、テンプレートでx-basicを指定します。

    ? Which template do you want to use? › - Use arrow-keys. Return to submit.
      ↑ cloudflare-pages
        cloudflare-workers
        deno
        fastly
        lambda-edge
        netlify
        nextjs
        nodejs
        vercel
    ❯   x-basic

    そのほかの設定は好みに任せて行いましょう。最後に次のような生成完了メッセージが出ればOKです。

    cloned honojs/starter#main to /Users/sandbox
    ✔ Copied project files

    呼び出すAPIを用意する

    外部APIを呼び出すテストですので、APIをまずは用意しましょう。Honoxはファイルベースでルーティングを処理しますので、追加したいAPIのパスと一致するファイルを作りましょう。例えばapp/api.tsxを作ると、/apiのパスでAPIが作れます。またNext.jsライクにメソッド名の変数をexportすることで、対応するメソッドを生やせます。そのため、GET /apiを作りたい場合は、このようなコードをapp/api.tsxに実装しましょう。

    import { createRoute } from "honox/factory";
    
    export const GET = createRoute(async c => {
        return c.json({
            message: 'hello'
        })
    })

    これで/apiに対するGETリクエストを処理できるようになりました。

    クライアント側でのfetchを試みる

    まずはクライアント側での呼び出しを試してみましょう。テンプレートにあるapp/islands/counter.tsxを次のように変更します。

    import { useState } from 'hono/jsx'
    
    export default function Counter() {
      const [message, setMessage] = useState("")
      return (
        <div>
          <p>{message}</p>
          <button onClick={async () => {
            const result = await fetch('/api')
            const data = await result.json<{message: string}>()
            setMessage(data.message)
          }}>Fetch</button>
        </div>
      )
    }

    ボタンクリック時のイベントでfetchを行い、useStateで値をコンポーネントに渡しています。

    Reactライクにかけるのが便利ですね。

    サーバー側でのfetchにトライする

    続いてサーバー側の処理も試してみましょう。今度はapp/routes/index.tsxを編集します。

    import { css } from 'hono/css'
    import { createRoute } from 'honox/factory'
    import Counter from '../islands/counter'
    
    const className = css`
      font-family: sans-serif;
    `
    
    export default createRoute(async (c) => {
      const name = c.req.query('name') ?? 'Hono'
      const result = await fetch(`${c.req.url}api`)
      const {message} = await result.json<{message: string}>()
      return c.render(
        <div class={className}>
          <h1>Hello, {name}!</h1>
          <h2>{message}</h2>
          <Counter />
        </div>,
        { title: name }
      )
    })
    

    c.renderに渡す値を、await fetchで取得しています。「Hello, 」の後ろ部分がAPIレスポンスになっていますので、次のような表示になるはずです。

    やってみての感想

    Reactっぽさもありつつ、Hono / Cloudflare Workersっぽい書き方もできるので、個人的にはhonoxはなかなか面白いなと思っています。Astroとかも使い勝手がよいなと思いますが、サーバー側の処理(コンポーネント・API)が多めのサイトやアプリについてはこちらで、どちらかというとSSG的な用途で使いたい場合はAstroかなぁというイメージですね。

    変更履歴

    • 2024/12/16: REST APIの作り方が変わっていたので、記事を参考に変更
    広告ここから
    広告ここまで
    Home
    Search
    Bookmark