🔥

🔥Honoを使ってCloudflare Workersアプリを書き換えてみた

2023/04/04に公開2件

Honoというフレームワークが気になっていたので使ってみました。
気になっていた理由は、名前が素敵だからです笑
4文字でミニマルなのも良いですね。
なんとなくウォッチしていたのですが、気づいたらかなり人気のフレームワークになっていました。

🔥Honoとは

Cloudflare Workers上で動かすことを目的に作られた軽量なWebフレームワークです。
https://github.com/honojs/hono

Hono - [炎] means flame🔥 in Japanese - is a small, simple, and ultrafast web framework for the Edge. It works on Cloudflare Workers, Fastly Compute@Edge, Deno, Bun, Vercel, Lagon, Node.js, and others. Fast, but not only fast.

この説明読んだ時にいいなと思って、いつか使いたいなと思ってました😊

ちなみに、Cloudflare Workersは、CDN(コンテンツデリバリーネットワーク)のエッジ上でJavaScriptコードを実行できるものです。
とても高速で、しかもデプロイがかなり簡単に素早くできるということで、ちょっとしたAPIを作成するのに最近よく使われています。

今回やったこと

今回はCloudflare Workersで動かしているAPIがあるので、それをHonoで書き直してみました。
こちらのプロダクトです。
https://github.com/yoonchulkoh/twit-calender

APIが1つだけの簡単なプロダクトになります。

使い方

README通りですが、

npm create hono@latest my-app

とすれば空のアプリができます。

僕はすでに既存コードがあったのでプロジェクトのディレクトリ上で、

npm create hono@latest .

として上書きして、必要なものをpushしてあるGitHubリポジトリからコピーしてきました。

書き換えた部分

主に下記になります。

  1. package.json
  2. 環境変数取得部分
  3. fetch関数→ルーティング

1. package.json

まっさらになっているので、元々使っていたライブラリ類を追加します。

2. 環境変数取得部分

環境変数の取得方法が変わっているので書き換えます。
Honoではinterfaceを定義する必要がなくなっています。

// 定義
export interface Env {
  TWITTER_BEARER_TOKEN: string;
  OPENAI_ORGANIZATION: string;
  OPENAI_API_KEY: string;
}

// 使う場所
const client = new Client(env.TWITTER_BEARER_TOKEN);

↓↓↓

app.get("/", async (c) => {
    const text = await getTweetTextById(
      // 定義は不要でそのまま使える
      c.env!.TWITTER_BEARER_TOKEN as string,
      tweetId
    );

tsエラーになるので、!やas stringを付けてるんですけど、ドキュメントでは付けていないんですよね。フレームワークと直接関係ないですが、ts力が弱くよくわからない部分でした。

3. fetch関数→ルーティング

Cloudflare Workersはリクエストを受けるとfetch関数が呼ばれるという仕組みです。Honoではルーティングの仕組みがあるので、このように実装します。

export default {
  async fetch(request) {
    return new Response(html);
  },
};

↓↓↓

import { Hono } from 'hono'
const app = new Hono()

app.get('/', (c) => c.text('Hono!'))

export default app

書き換えたコミットはこちらです。
https://github.com/yoonchulkoh/twit-calender/commit/a778a780dba43314cf8cb235234e7cdc4337572a

ちょっと困ったこと

既存コードでは、処理ごとに関数化していました。
https://github.com/yoonchulkoh/twit-calender/blob/af1ebb87f0e21916180f83d8d7d5a5de6d00406f/src/index.ts

その関数にCloudflare Workersで使われるRequestやEnvを渡していました。
Honoでも同じように(なるべく元の構成を変えたくなかったので)、Contextを関数に渡したいなと思いました。
しかし、関数側にどのような型定義をすればよいのかわからず、ts力の無さを痛感しました。


やりたいのはこういうことです、と改めて書いてみたら出来ました。。
ただ、"/sample"とpathを型に文字列で書くのはこういうものなんだろうか、というところがまだ理解が浅い部分です。ちゃんと理解しておきたい部分です。

まとめ

簡単ですが、🔥Honoを使ってみた紹介でした。

今回はAPIが1つだけだったのであまりメリットはないですが、ルーティングが簡単にできるのはとても魅力的ですね。これがないと自分でURLを見て切り替えなければいけないので。
使い方もとてもかんたんでした。

次はこのプロダクトに画面を一つ追加したいなと思っています。
テキストを受け付けて結果を返す簡単なフォームです。
HTML直で書くのはちょっとな、と思っていたらJSX Middlewareというのを見つけたので、これを使ってみようと思います。
Reactで使われているJSX syntaxをHonoで使えるようにするものです。
https://hono.dev/middleware/builtin/jsx

Cloudflare Workers&Honoを使えるようにしておくと、ちょっとしたものをさくっと作って公開できるのでとても便利です。
みなさんもぜひ使ってみてください。

レスキューナウテックブログ

Discussion

yusukebeyusukebe

こんにちわ!Honoの作者です。使ってくれてありがとうございます!!ドキュメントが不十分だったりして、わかりにくかったかもですね。いくつか気づいたので補足させてください。

まず、環境変数ですが、Honoを使うか使わないかに関わらず、型定義なくとも値は取得できます。Honoの場合は以下のようにTypeを渡すことで、補完が効くようになります。

type Bindings = {
  TWITTER_BEARER_TOKEN: string
  OPENAI_ORGANIZATION: string
  OPENAI_API_KEY: string
}

const app = new Hono<{ Bindings: Bindings }>()

SS

クエリのパースはc.req.query()を使えば簡単にできます。

const tweetUrl = c.req.query('tweetUrl')

次に、ハンドラの中をtry/catchで囲っているようですが、 Honoはエラーのハンドリングを自動でするので、とりわけその必要はないと思います。

また、new Response('..')してるところは、c.text()などのショートカットが使えます!

return c.text(calendarUrl)

これはHono関係なくなっちゃいますが、Cloudflare WorkersではWeb StandardのAPIが使えるのでクエリパラメータの作成などはURLSearchParamsを使うとよさげです。

const urlParams = new URLSearchParams(params).toString()

自分なりにリファクタしたコードは以下になります。

https://github.com/yusukebe/twit-calender/blob/main/src/index.ts

なんか色々コメントしてすいません。ドキュメントを分かりやすくするのと、増やすのがんばります!

yoonchul kohyoonchul koh

わー、色々とコメントありがとうございます!
HonoはyusukebeさんのTwitter見てずっと気になってたのでコメントもらえて嬉しいです!

リファクタしたコードまでありがとうございます。
参考に書き直してみます😊