Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
HonoのRPCで真の型安全が欲しかった
Search
kosei28
May 18, 2024
Programming
1.5k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
HonoのRPCで真の型安全が欲しかった
kosei28
May 18, 2024
Other Decks in Programming
See All in Programming
Claude Codeを組織的に動かして月400PRを実現した話
happy_ryo
0
260
異なる設計思想のフレームワークを経験して得た学び
amekuhideki
2
1.5k
業務時間外もAIに働いてもらう話
colorful12
3
10k
【DroidKaigi 2026】「アクセシビリティを利用するとき、 アクセシビリティもまたこちらを利用している」 〜マルウェアによる攻撃と防衛について〜
halunoyo
0
410
DynamoDBの基礎を振り返りながらベクトル検索機能を理解する
musan
3
270
個人開発基盤をまるごとCloudflareに引っ越して爆速で総合的体験を向上させた話
tinykitten
0
110
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
160
AIと壁打ちしながら進めるコスト管理
fufuhu
2
1.9k
『寄り添うラジオ』をAIで作る 体験価値から逆算した、会話しないUXと品質設計
theoriatec2024
3
130
Webプラットフォームで議論されているセキュリティ課題 / Security issues being discussed on Web Platforms
petamoriken
0
170
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
120
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
2
2.5k
Featured
See All Featured
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
520
Art, The Web, and Tiny UX
lynnandtonic
304
22k
The Spectacular Lies of Maps
axbom
PRO
1
980
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
410
BBQ
matthewcrist
89
10k
Utilizing Notion as your number one productivity tool
mfonobong
4
570
Mind Mapping
helmedeiros
1
350
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
440
Designing Dashboards & Data Visualisations in Web Apps
destraynor
232
55k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.4k
GitHub's CSS Performance
jonrohan
1033
470k
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.4k
Transcript
HonoのRPCで 真の型安全が欲しかった kosei28
kosei28 • 個人開発でWebやってます • TypeScript大好き ◦ フロントエンドもバックエンドも! • (一応)Honoのコントリビューター 𝕏:
@kosei_28
Honoとは • JS/TSのWebフレームワーク • 高速、軽量 • あらゆるJavaScriptランタイムで動作する ◦ エッジ環境でよく使われる •
RPCモード ◦ サーバーの型をクライアントと共有して型安全に API呼び出しができる機能
RPCモードを使ってみる import { Hono } from "hono"; import { z
} from "zod"; import { zValidator } from "@hono/zod-validator" ; const app = new Hono(); const routes = app.get( "/greeting" , zValidator ("query", z.object({ name: z.string() })), (c) => { const { name } = c.req.valid("query"); return c.json({ message: `Hello, ${name}!` }); } ); export type AppType = typeof routes; export default app; import { hc } from "hono/client" ; import type { AppType } from "./server" ; const client = hc<AppType>("/"); const res = await client.greeting.$get({ query: { name: "kosei28" }, }); const data = await res.json(); // { message: string; } console.log(data.message); // “Hello, kosei28!” server.ts client.ts
実は完璧な型安全ではない😭
Middlewareで返したResponseには型がつかない const error = true; app.use(async (c, next) => {
if (error) { return c.json({ error: "Internal Server Error" }, 500); } await next(); }); server.ts client.ts const res = await client.greeting.$get({ query: { name: "kosei28" }, }); const data = await res.json(); // { message: string; } console.log(data.message); // undefined console.log(data.error); // “Internal Server Error”
• Middlewareで極力Responseを返さない ◦ Middlewareの代わりに関数を用意して各ルートから呼び出す ◦ Middlewareの恩恵をあまり受けられない • ValidatorもMiddleware ◦ Zod
Validatorのバリデーションエラーによる Responseはどうにもできない ◦ そもそもバリデーションエラーを発生させない ▪ Validatorでのバリデーションは型チェックだけにする ▪ リクエスト前にクライアントでもバリデーションする • スキーマを別のモジュールに定義して、サーバー・クライアントで共有する 対策1: Middlewareで返すResponseをどうにかする
対策2: 各ルートのResponseは全て200番台で返す • Response.okでResponseがMiddlewareによるものか判別できる ◦ Middlewareでは200番台のResponseを返さない • デメリット ◦ 不適切なステータスコード?
▪ GraphQLは全て200 ▪ 割り切ってしまえるなら問題なし ◦ 結局、MiddlewareのResponseの型はわからない ◦ ステータスコードによる型の分岐が使えない
const routes = app.get( "/greeting" , zValidator ("query", z.object({ name:
z.string() })), (c) => { const { name } = c.req.valid("query"); if (error) { return c.json({ success: false as const, error: "Internal Server Error" , }); } return c.json({ success: true as const, data: { message: `Hello, ${name}!` }, }); } ); res.okの場合は型安全 const res = await client.greeting .$get({ query: { name: "kosei28" }, }); if (res.ok) { // この中では型安全 const result = await res.json(); if (result.success) { console.log(result.data.message); } else { console.log(result.error); } } server.ts client.ts
まとめ • HonoのRPCモードはとても便利だが真の型安全ではない • 対策 ◦ MiddlewareによるResponseを減らす ◦ クライアントでもバリデーションすることが重要 ◦
各ルートのResponseを200番台で返せば部分的な型安全にできる • 型があるからと言って安全ではない ◦ TypeScriptはデータと全く異なる型をアサーションできてしまう ◦ 気づかぬうちに大事故が起こるかも …