Slide 1

Slide 1 text

Honoとフロントエンドの 型安全性について Findy LunchLT Hono活用を徹底解説 先達に学ぶベストプラクティス 2025-02-18 yodaka

Slide 2

Slide 2 text

自己紹介 よだか - フリーランス、WebDeveloper - Next.js / Hono / Laravel / Vue.js / TypeScript - 最近Flutterも - TSKaigiスタッフ - 開催:2025年5月23日-24日 2Days - 会場:ベルサール神田 - 趣味で音楽を作ってます - 映画や小説が好き

Slide 3

Slide 3 text

この発表のテーマ(持ち帰って欲しいもの) Honoを使用して、どのようにマルチクライアント( WEB/アプリ)の型 安全な開発を実現しているか、その魅力

Slide 4

Slide 4 text

アジェンダ 1. What’s Hono? 2. Hono採用の経緯 3. どうやって型安全な開発をしているか 4. Next.jsとHonoのRPCによる連携 5. FlutterとHonoのOpenAPIによる連携 6. インフラ・改善点など小噺 7. まとめ

Slide 5

Slide 5 text

What’s Hono? - 割愛!

Slide 6

Slide 6 text

What’s Hono?(ちょっとだけ) - ランタイム差異を吸収するポータビリティ - > Cloudflare Workers, Fastly Compute, Deno, Bun, AWS Lambda,... - Web標準 - https://wintercg.org/(WinterTC) - 軽量・高速 - > Hono x 402,820 ops/sec ±4.78% (80 runs sampled) - > The hono/tiny preset is under 14kB. Hono has zero dependencies and uses only the Web Standards. - 豊富なミドルウェア、カスタマイズ性 - CORS、CSRF、JWT、Logger… - RPCやミドルウェアを使った、フロントエンドとの型共有

Slide 7

Slide 7 text

What’s Hono?(ちょっとだけ) - ランタイム差異を吸収するポータビリティ - > Cloudflare Workers, Fastly Compute, Deno, Bun, AWS Lambda,... - Web標準 - https://wintercg.org/(WinterTC) - 軽量・高速 - > Hono x 402,820 ops/sec ±4.78% (80 runs sampled) - > The hono/tiny preset is under 14kB. Hono has zero dependencies and uses only the Web Standards. - 豊富なミドルウェア、カスタマイズ性 - CORS、CSRF、JWT、Logger… - RPCやミドルウェアを使った、フロントエンドとの型共有  ←ココ

Slide 8

Slide 8 text

アジェンダ 1. What’s Hono? 2. Hono採用の経緯 3. どうやって型安全な開発をしているか 4. Next.jsとHonoのRPCによる連携 5. FlutterとHonoのOpenAPIによる連携 6. インフラ・改善点など小噺 7. まとめ

Slide 9

Slide 9 text

Hono採用の経緯 ・こんな別プロジェクトがあった ・Go->OpenAPI->SWR

Slide 10

Slide 10 text

Hono採用の経緯 ・GoからOpenAPIを吐き出すのも、OpenAPIからSWRのクライアントを吐き出すのも癖 があって結構つらい ・Goは色々肌に合わなかった

Slide 11

Slide 11 text

Hono採用の経緯 そもそも ・バックもフロントも自分で書けるのに、型欲しさにOpenAPIを生成しているのは遠回り している ・GraphQLなどの選択肢もあったのか?とは思うが、そのプロジェクトはマルチクライア ントでもないし、あまり詳しくなかった

Slide 12

Slide 12 text

Hono採用の経緯 ・HonoのRPCモードが出たタイミングで、新規プロジェクト(この後説明で使う予約シス テム)でHonoを推してみたらあっさり採用された🔥🔥🔥 ・Honoに変えることで型安全かつ、非常に高速な開発が可能になった ・アプリ用のサーバーにもHonoのOpenAPI用のミドルウェアで対応できた (ZodOpenAPIHonoのおかげで実装と型が食い違いにくくなった)

Slide 13

Slide 13 text

アジェンダ 1. What’s Hono? 2. Hono採用の経緯 3. どうやって型安全な開発をしているか 4. Next.jsとHonoのRPCによる連携 5. FlutterとHonoのOpenAPIによる連携 6. インフラ・改善点など小噺 7. まとめ

Slide 14

Slide 14 text

今回の発表に使用するプロジェクトの説明 ・アプリ(Flutter)、WEB(Next.js)、管理画面(Next.js)の3つフロントがある ・飲食店の方とそのお客さんが使う予約システムみたいな感じ ・これをHonoのサーバー一つで捌く ・WEB、管理画面、バックエンドはpnpmでモノレポ構成にしてある

Slide 15

Slide 15 text

予約アプリの構成概要 アプリ(Flutter)、WEB(Next.js)、管理画面(Next.js)の3つフロントがある

Slide 16

Slide 16 text

どうやって型安全な開発をしているか -> Next.jsには型をRPCで渡し、アプリには OpenAPIで型を渡す これのやり方について今日は話していきます

Slide 17

Slide 17 text

ちなみにどういう設計・構成にしているか? - こちらの記事を参照 Honoマイベストプラクティスhttps://zenn.dev/yodaka/articles/ad49f29a54ceba

Slide 18

Slide 18 text

アジェンダ 1. What’s Hono? 2. Hono採用の経緯 3. どうやって型安全な開発をしているか 4. Next.jsとHonoのRPCによる連携 5. FlutterとHonoのOpenAPIによる連携 6. インフラ・改善点など小噺 7. まとめ

Slide 19

Slide 19 text

Next.jsとHonoのRPCによる連携

Slide 20

Slide 20 text

予約アプリの構成概要

Slide 21

Slide 21 text

HonoのAPI定義 const adminRouter = new Hono().post( '/posts', zValidator( 'json', z.object({ title: z.string(), body: z.string(), }) ), (c) => { // 型がついている const { title, body } = c.req.valid(‘json’) } ) type Form = { title: string body: string }

Slide 22

Slide 22 text

Honoからエクスポートした型をNext.jsに渡す(Hono側) const app = new Hono() .route('/sp', spRouter) .route('/web', webRouter) .route('/admin', adminRouter) export type AdminAppType = typeof adminRouter export type webRouter = typeof webRouter

Slide 23

Slide 23 text

Honoからエクスポートした型をNext.jsに渡す(Next.js 側) import { hc } from 'hono/client' import { AdminAppType } from 'backend/src' // typesafeなAPIClientとして使える。 const client = hc(baseUrl, { headers, })

Slide 24

Slide 24 text

Honoからエクスポートした型をNext.jsに渡す // クライアント import { hc } from 'hono/client' import { AdminAppType } from 'backend/src' // typesafeなAPIClientとして使える。 const client = hc(baseUrl, { headers, }) // サーバー const app = new Hono() .route('/sp', spRouter) .route('/web', webRouter) .route('/admin', adminRouter) export type AdminAppType = typeof adminRouter export type webRouter = typeof webRouter

Slide 25

Slide 25 text

Next.js側 APIクライアント使用例 // パスも型がついている const res = await client.posts.$post({ json: { // request bodyも型がついてる title: 'Hello', body: 'Hono is a cool project', }, }) type Form = { title: string body: string }

Slide 26

Slide 26 text

SWRから利用する こちらを参照 https://github.com/yodakaEngineer/hono-swr-example/tree/main

Slide 27

Slide 27 text

SWRから利用する ・こんな感じでhcに型定義 渡す

Slide 28

Slide 28 text

SWRから利用する ・InferRequestTypeなどが あるので、基本的にバック エンドから渡すのはHono のRouterの型だけで済む ・Zodの定義もバリデーショ ンをバックとフロントで共有 したい場合はexportする

Slide 29

Slide 29 text

tRPCでもいいんじゃないの? ・tRPCはRPCを実現したい、HonoはAPIを実装するだけでクライアントに型を提供した いといった具合に、そもそも目指しているものが違う ・Honoはあくまでルーター、サーバーであるが故の強みがある ・tRPCはRPCである強みがある ・今回のアプリのクライアントはFlutterなのでtRPCできない

Slide 30

Slide 30 text

tRPCでもいいんじゃないの?

Slide 31

Slide 31 text

アジェンダ 1. What’s Hono? 2. Hono採用の経緯 3. どうやって型安全な開発をしているか 4. Next.jsとHonoのRPCによる連携 5. FlutterとHonoのOpenAPIによる連携 6. インフラ・改善点など小噺 7. まとめ

Slide 32

Slide 32 text

FlutterとHonoのOpenAPIによる連携

Slide 33

Slide 33 text

予約アプリの構成概要

Slide 34

Slide 34 text

Zod OpenAPI HonoでOpenAPIを生成する ・router(実際の処理)とは別でroute(OpenAPIのス キーマ)を定義する ・パスパラメータやリクエストの Body、レスポンスの BodyなどをZodを使って定義できる。

Slide 35

Slide 35 text

Zod OpenAPI HonoでOpenAPIを生成する ・zodを拡張したものでリクエスト、レスポンス、パス パラメータ、クエリパラメータなどのスキーマを定義 する ・OpenAPIに表示したいexampleなどがこれで定義 可能

Slide 36

Slide 36 text

Zod OpenAPI HonoでOpenAPIを生成する ・OpenAPIHonoインスタンスのopenapiメソッドの 第一引数に先ほどの routeを渡す ・第二引数のコールバックの戻り値( return c.json の部分)の型がrouteと違うとエラーを出してくれ る。 ・c.req.validの戻り値もrouteに定義したスキーマ が 推論される ・つまり、 OpenAPIと実装が異なるということが防 げる!

Slide 37

Slide 37 text

Zod OpenAPI HonoでOpenAPIを生成する ・もちろん、HonoでOpenAPIをホスティングできま す! ・これはJSONが返ってくるが、別で SwaggerUIのミ ドルウェアもあり、それを使うと webサイトとして公 開できる ・これをFlutterのリポジトリから叩くことで、 OpenAPIのスキーマを取得し、 APIクライアントを生 成する

Slide 38

Slide 38 text

OpenAPIからFlutter用のAPIクライアントを生成する ・先ほどのOpenAPIのJSONが返ってくるAPIにリクエストし、ymlファイルに変換するス クリプトを組んである ・そのymlからOpenAPI GeneratorでAPIクライアントを生成する https://github.com/OpenAPITools/openapi-generator

Slide 39

Slide 39 text

これによって型安全なクライアント開発が可能に!

Slide 40

Slide 40 text

GraphQLでも良かったんじゃないの? ・それはそう ・技術検証ができてないので、今度小さく使ってみる予定

Slide 41

Slide 41 text

アジェンダ 1. What’s Hono? 2. Hono採用の経緯 3. どうやって型安全な開発をしているか 4. Next.jsとHonoのRPCによる連携 5. FlutterとHonoのOpenAPIによる連携 6. インフラ・改善点など小噺 7. まとめ

Slide 42

Slide 42 text

せっかくだしちょっとインフラの話 - HonoをECSコンテナ上のNode.jsで動かしている - Cloudflare Workerで動かしたいが、WorkerからアクセスするにはAWSのVPC内 のRDSをパブリックにしないといけないor踏み台を立てないといけない? - 詳しい人、情報求む

Slide 43

Slide 43 text

改善点 ・RPCはメソッドチェインさせた戻り値の型をフロントに渡しているが、Zod OpenAPIは OpenAPIHonoクラスがHonoインスタンスを拡張した別ものなので、チェインできなくて 困ることがある(.use()などの戻り値がオリジナルのHonoインスタンスになってしまう) -> これは普通にRPCとOpenAPIHonoを一緒に使わないことで回避可能。

Slide 44

Slide 44 text

改善点 - ミドルウェアの型周りのベストプラクティスがまだあまりわかっていない - 特定のmiddlewareを通ったあとにだけcontextに型を入れるみたいなことをうまくやりたい - 最近徐々にサポートが厚くなってきている印象( createRouteのmiddlewareも型がつくようになっ たり) - アプリがReact NativeだったらアプリもRPC出来て…?? - より幸せになれる

Slide 45

Slide 45 text

まとめ - Honoを使うことで型安全な開発が余計なことを意識せずに できる。 - 実装と型定義の乖離や、フロントに渡すためだけの型を頑張って書くなどしなくて良い - 開発生産性がとても上がった。 - 型はもらえるし、フロント、バックのコンテキストスイッチコストもない( FullStackTSの話)

Slide 46

Slide 46 text

Honoを使って最高の開発体験を!

Slide 47

Slide 47 text

引用・参考文献 - Hono 公式ドキュメント - https://hono.dev/ - TRPC 公式ドキュメント - https://trpc.io/ - SWRのサンプル - https://github.com/yodakaEngineer/hono-swr-example - 構成参考記事 - https://zenn.dev/yodaka/articles/ad49f29a54ceba

Slide 48

Slide 48 text

Thank you!