【dnt】Hono RPCのAPIスキーマをnpmパッケージ化する
はじめに
サーバーサイドを Deno、クライアントサイドを Node といった技術スタックでリポジトリを分けて開発する際に、Hono RPC の API スキーマ共有方法が課題になりました。
まずは Git Submodule での解決を目指しましたが、
- リポジトリの複雑化&管理の難しさ
- Path Alias の回避
- ランタイムの違い
が課題になりました。
その中でdntを使い、サーバーサイドの API スキーマを npm パッケージ化し、クライアントサイドでそのパッケージを利用することで解決できたので、この記事ではその手法を紹介します。
dnt とは
dnt は npm パッケージを Deno で作成するためのライブラリです。
本記事では dnt については詳しく説明しないので、詳細は公式ドキュメントを参照してください。
npm パッケージ化の手順
今回の記事では『サーバーサイドの Hono RPC の API スキーマを npm パッケージ化し、ローカルのクライアントサイドプロジェクトで利用できること』をゴールにします。
環境
今回の環境は以下の通りです。
- deno
1.46.2
- node
20.17.0
- npm
10.8.2
パッケージ化するプログラム
今回は以下のサーバーサイドのソースをパッケージ化します。
$/
は Path Alias です。
import { Hono } from 'hono'
import { z } from 'zod'
import { zValidator } from '@hono/zod-validator'
const hello = new Hono()
.get(
'/',
zValidator(
'query',
z.object({
name: z.string(),
}),
),
(c) => {
const { name } = c.req.valid('query')
return c.json({ message: `Hello, ${name}!` })
},
)
export default hello
import { Hono } from 'hono'
import helloApp from '$/hello-router.ts'
const app = new Hono()
const routes = app
.route('/hello', helloApp)
export type AppType = typeof routes
export default app
また、プロジェクトで使用する依存関係はdeno.jsonc
に定義している前提です。
{
"imports": {
"hono": "jsr:@hono/hono",
"zod": "https://deno.land/x/zod/mod.ts",
"@hono/zod-validator": "npm:@hono/zod-validator",
}
}
サーバー起動用のハンドラは別ファイルへ...
サーバー起動用のハンドラは以下のように別ファイルに分けています。
import app from '$/app.ts'
Deno.serve(app.fetch)
理由としては dnt でのパッケージビルド時にProperty 'serve' does not exist on type 'typeof Deno'.
というエラーが出たためです。
私自身の dnt に対する知識不足でこのエラー回避方法が分かりませんでした...。
今回は Hono RPC の API スキーマの npm パッケージ化が目的なので、このハンドラの部分は省略します。
1. ビルドスクリプトの作成
それではビルドスクリプトを作成します。
まずは dnt をインストールします。
$ deno add @deno/dnt
次にビルドスクリプトを作成します。
今回のパッケージ名はtest-deno-hono-schema
とします。
また、ビルドファイル名はnpm-build.ts
にし、npm
ディレクトリ下にビルド物を出力するようにします。
設定は最低限動くものなので、詳細な設定は dnt のドキュメントを参照してください。
import { build, emptyDir } from '@deno/dnt'
await emptyDir('./npm')
await build({
entryPoints: ['./app.ts'],
outDir: './npm',
test: false,
shims: {
deno: true,
},
importMap: 'deno.jsonc',
package: {
// package.json properties
name: 'test-deno-hono-schema',
version: Deno.args[0],
description: 'Test Deno Hono Schema.',
},
})
準備は完了です。
2. npm パッケージのビルド
それでは npm パッケージをビルドします(バージョンは0.1.0
にしています)。
$ deno run -A npm-build.ts 0.1.0
ビルドに成功するとnpm
ディレクトリが作成され、その中に npm パッケージが出力されます。
このディレクトリをクライアントサイドのプロジェクトに配置します。
3. 作成した npm パッケージをクライアントサイドで使用する
クライアントサイドのプロジェクトにて、作成した npm パッケージをインストールします。
$ npm install ./npm
あとはクライアントサイドのプロジェクトでインポートして使用するだけです。
import { hc } from "hono/client";
import type { AppType } from 'test-deno-hono-schema'
const client = hc<AppType>("http://localhost:8080");
const res = await client.hello.$get({ query: { name: "world" } });
if (res.ok) {
const json = await res.json();
console.log(json.message);
}
おわりに
以上が dnt を使って Hono RPC の API スキーマを npm パッケージ化し、クライアントサイドで利用する方法を紹介しました。
今回はローカル環境での利用を前提にしていますが、CI/CD で npm パッケージのビルド等を行っても良さそうです。
参考記事
Discussion