🔥

Hono でつくる、うすい URL 短縮

2024/12/14に公開

この記事は MICIN Advent Calendar 2024 の 14 日目の記事です。

https://adventar.org/calendars/10022

前回は mimusalon さんの、「脆弱性診断を外部委託したときの手順をまとめてみる」 でした。

はじめに

私は通院専用キャッシュレス決済サービスクロンスマートパスの開発・運用・保守を担当しています。クロンスマートパスの 1 つの機能として、短縮 URL をユーザに対して通知するというものがあります。

今回は要件を満たすため、Hono と Vercel Edge Functions を採用しました。結果として、感動レベルで薄い URL 短縮 API を実装できました。ここでは、実装からデプロイまでの手順について記載します。

構成

構成として、ベースは Hono を用い、Vercel Functions の Edge Runtime 上で動作をさせています。DB は Vercel Postgres を利用しています。

実装

実装したリポジトリは以下となります。

https://github.com/ryoshindo/shourlt

実装は一瞬で読み終わるくらいに薄い実装です。すべての実装を貼付しても良いくらいには薄いのですが、どれくらい薄いかというのは package.json をご覧いただくのが最もクリアに伝わるかと思います。

package.json
{
  "name": "shourlt",
  "scripts": {
    "start": "vercel dev -l 3100",
    "deploy": "vercel"
  },
  "dependencies": {
    "@vercel/postgres": "^0.10.0",
    "hono": "^4.6.13"
  },
  "devDependencies": {
    "vercel": "^32.4.1"
  }
}

Hono 本体と PostgreSQL にアクセスするためのライブラリである @vercel/postgres をインストールするのみで、サーバが動作します。

認証としては、いたずらされないように申し訳程度の Basic 認証は行っています。

利用上の注意点

今回実装した API は想定するリクエスト数がそれほど多くないと見積もられるため、slug 部分の衝突を考慮した実装としていません。そのため、乱数生成のライブラリ等を導入せずに Math.random().toString(36).substring(7) を用い slug を生成しています。リクエストが多く衝突可能性が高い場合は、

  • 高度な乱数生成のアルゴリズムを用いる
  • 衝突した場合はリトライする

等の修正が必要となります。

デプロイまでの手順

プロジェクト作成からデプロイまでの手順は非常にシンプルです。要領よくパパッと実装できれば、まっさらな状態からでも 30 分あればデプロイまでできるかと思います。

Hono プロジェクトの作成

まずはプロジェクトを作成します。

pnpm create hono my-shourlt

実装

アプリケーション実装します。下記リポジトリ(先ほど貼付したもの)を参考にしてみてください。

https://github.com/ryoshindo/shourlt

Vercel Postgres を作成

Vercel アカウントを作成し、サーバーレスな PostgreSQL DB を作成します。Vercel アカウント内で 1 つ目の DB は Hobby プランの無料枠で含まれるため、無料で利用できます。

https://vercel.com/docs/storage/vercel-postgres/usage-and-pricing

ちなみに、DB の作成は一瞬で完了します。他クラウドだと DB 作成が完了するまで 10 分以上要することもあるため、急ぎのときに一瞬で DB の用意が完了するというのは非常にありがたいです。

マイグレーションを実行

Vercel Postgres を作成すると、Neon のダッシュボード上で SQL を実行できるようになります。下記マイグレーションを実行します。

20241214_init.sql
CREATE TABLE "targets" (
    "id" TEXT PRIMARY KEY NOT NULL,
    "url" TEXT NOT NULL,
    "slug" TEXT NOT NULL UNIQUE,
    "created_at" TIMESTAMP NOT NULL DEFAULT NOW()
);

環境変数の設定

Vercel Postgres ダッシュボードから DB Credential をコピーし、.gitignore に登録されている .env にペーストします。また、ドメインも登録します。

POSTGRES_URL=postgres://aaa:bbb@ccc-pooler.us-east-1.aws.neon.tech/neondb?sslmode=require
SHOURLT_URL=http://localhost:3100

ローカルでの動作確認

ここまで来るとローカルでサーバを起動し、動作確認ができます。

pnpm start

上記コマンドを実行すると Vercel Project の初期設定も同時に行うことができます。

以下の cURL コマンドでサーバに対してリクエストを送信してみます。このリクエストは昨年の Advent Calendar にて私が執筆した記事に対しての URL 短縮しています。

curl -X POST \
    -u user:password \
    -H "Content-Type: application/json" \
    -d '{"url": "https://zenn.dev/micin/articles/ecb422db4b4f67"}' \
    http://localhost:3100/api/targets

下記のようなレスポンスが来ます。

{ "origin": "http://localhost:3100/t0z1je" }

このレスポンスをサービス側で表示させると、もともとの URL(今回の場合は https://zenn.dev/micin/articles/ecb422db4b4f67 )にリダイレクトされます。

デプロイ

Vercel のダッシュボードで先程 pnpm start 時に作成した Vercel Project を選択し、環境変数として SHOURLT_DOMAIN の値を設定します。ちなみに、DB Credential は Vercel 側で既に登録してくれています。

以下のコマンドで Vercel にデプロイします。

pnpm push

デプロイは 20 秒弱で完了します。かなり高速です。

動作確認

デプロイしたサーバに対してリクエストを送信してみます。

curl -X POST \
    -u user:password \
    -H "Content-Type: application/json" \
    -d '{"url": "https://zenn.dev/micin/articles/ecb422db4b4f67"}' \
    https://my-shourlt.vercel.app/api/targets

ローカルでの動作確認と同じようなレスポンスが来ることが確認できれば、作業はすべて完了です。

さいごに

さいごまで読んでいただきありがとうございました。

実際にクロンスマートパスの本番環境のドメインは美しいものを採用しているつもりです。アカウント登録して、探してみてね 🔥


MICIN ではメンバーを大募集しています。
「とりあえず話を聞いてみたい」でも大歓迎ですので、お気軽にご応募ください!
https://recruit.micin.jp/

GitHubで編集を提案
株式会社MICIN

Discussion