😮

HonoでURL短縮サービスを作ろうと思ったら逆に長くなった話

2024/02/14に公開

Raycastの拡張機能を作成しました

みなさんは普段どんなランチャーアプリを使用していますか?

macOS標準のSpotlightですか、それともサードパーティ製のツールでしょうか。
僕はRaycastというアプリを使っています。

Raycastはそのカスタマイズ性の高さから多くの開発者に支持されており、さらに拡張機能をTypeScriptで開発できるという特徴を持っています。

今回はRaycastの拡張機能としてSurlというURL短縮サービスを開発したのでその詳細と裏側のサーバーの話をしようと思います。

https://x.com/fujiyamaorange/status/1751463257192472614?s=20

作ったもの

拡張機能はとてもシンプルで以下の2つの機能しか持ちません。

  1. URL短縮
    • 受け取ったURLを短縮して自動でクリップボードにコピーしてくれる
  2. 履歴検索・削除
    • 短縮したURLの履歴を見ることができる
    • 履歴を検索・削除できる

URL短縮

URL短縮の動画

履歴検索・削除

履歴検索・削除の動画

OSSでのPRマージまでの流れ

Raycastの拡張機能はGitHubにより管理されており、PRをマージすることで拡張機能をリリースすることができます。

OSSにPRがマージされたのは今回が初めてなのでPR作成からフィードバックをもらい修正、マージするまでの流れ、体験したことを共有します。

1. PR作成

親切なことにRaycastは拡張機能作成の手順、PR作成時の注意点などを公開してくれています。
基本的にはこれに沿って、十分に確認をしてからPRを作成します。

お互いの時間を節約するという点でこのようなルールを守ることは非常に大切です。

https://developers.raycast.com/basics/create-your-first-extension

2. フィードバックをもとに修正

正直ここが一番大変なステップです。

幸いRaycastは拡張機能をとても大切に考えているということもあり、素早いレビュー・手厚いフィードバックが提供されています。僕のレビューは@pernielsentikaerさんが担当してくださりました。

僕がもらったレビューは

  • 履歴検索機能を入れた方が良い
  • コマンドを分割した方が良い
  • no-viewコマンドにした方が良い

などでした。
上記のレビューは本当に的を射たものばかりで、今では最初に実装した機能を見ると恥ずかしくなるほどです。

これらのフィードバックをもとに機能を追加・修正し、再度フィードバックをもらうというやりとりを数回繰り返しました。

3. PRをマージ

そしてやっとの思いで良い拡張機能が出来上がりリリースすることができました🎉

PRを出してから「絶対に拡張機能を公開したい」と思っていたのでとても嬉しかったです。
その意思が伝わったのか、最後はレビュワー自身が細かい修正を加えてくれマージしてくれました(笑)。

所感

一連の流れの中で良かったポイントを挙げるとするなら、拡張機能のアイディアだと思っています。
Raycastでは1日にいくつもの拡張機能PRが挙げられており、その半分くらいがマージされる前にクローズされています

既存の拡張機能に似ているもの、レビュワーが魅力を感じなかったものは躊躇なくコメントで指摘されます。
そういった意味で「URL短縮を数ステップでできる拡張機能」のアイディアは悪くなかったのではと感じています。

https://github.com/raycast/extensions/pull/10031

Honoで作ったURL短縮サーバー

ここからはRaycastの拡張機能で使用している「URL短縮サーバー」の話をしようと思います。
タイトルに紐づくのはこっちの内容です。

HonoとCloudflare KV

今回のURL短縮サーバーはHonoで作成しました。
先日のYAPC@yusukebeさんがv4についての発表をされていましたね。非常にアツいフレームワークのひとつです🔥

データベースにはCloudflare KVを使っており、非常にシンプルな構成です。

  • URLを受け取り、短縮後のパスとなるキーを生成しKVに保存
  • アクセスがあった場合はKVからキーに該当するURLを取得し、リダイレクトする

おそらく上記の機能だけならサンプルの実装を見れば実現できます。

しかしそれだけだと味気なく面白みがないので若干の工夫を施しました。

工夫したところ

Scheduled Handler

Cloudflareは定期的にjobを実行できるScheduled Handlerという機能を提供しています。

今回はこれを使って有効期限切れのURLをKVから削除するという対応をしました。というものCloudflare KVは無料版だとデータ量が1GBまでと決まっています。
短縮したURLに有効期限を持たせ、期限切れの場合は再発行してもらうことでDBの容量増加を抑えています。

これに関して今は有効期限を1週間と設定しているので、今後は設定で変えられるようにしたいです。

https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/

UserAgent制御

もう1点DBへの負荷を軽減するためにUserAgentでの制御を行いました。

今回はURL短縮サーバーを自前で用意しているので大量にリクエストが送られてしまうとDBがすぐにパンクしてしまいそうです。

そのため以下のようにnode-fetch以外からのリクエストに関しては全て400を返すようにしています。

index.ts
const userAgent = c.req.raw.headers.get('user-agent')
if (userAgent !== 'node-fetch') {
  console.log(userAgent)
  return c.text('Invalid Request', 400)
}

これによりcurlやブラウザからのリクエストを遮断することができます。

まとめとこれからやること

ここまであまり話がまとまりませんでしたが、読んでくださりありがとうございます。まだまだやるべきこと・やりたいことはあり、一部をまとめてみました。

さらにURLを短くする

上記のようにRaycastでURL短縮の拡張機能をリリースできたわけですが、まだ重要な非機能要件を達成できていません。

その要件とは渡したURLが短くなることです(笑)。

現在はドメインにsurlapp.uk、パスとなるキーに8文字のランダムな文字列を使用しているので以下のようなURLになります。

https://surlapp.uk/XXXXXXXX

つまりこれよりも短いURLの場合、逆に長くなってしまうということです。今回はCloudflare Registrarでドメインを取得したのですがアプリに関係するドメイン名でこれより短いドメインを取得することができませんでした。😭

衝突の可能性

今はキーの生成にnanoidというライブラリを使用しているのですが、生成時に衝突の検証をしていません。

有効期限チェックによりDBを更新しているので確率はそれほど高くないですが、万が一起こった場合、不整合が起こる可能性があります。

こちらに関しては随時実装していこうと思います。

作ったもの

https://www.raycast.com/fujiyamaorange/surl

Discussion