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
まだ間に合う!今年の夏こそSchemeのマクロ展開器を完全理解!
omasanori
0
640
【DroidKaigi 2026】「アクセシビリティを利用するとき、 アクセシビリティもまたこちらを利用している」 〜マルウェアによる攻撃と防衛について〜
halunoyo
0
410
MIZARU@SPAJAM2026 第二回予選
1901drama
0
110
スマート反転とウェブアクセシビリティ
camiha
0
140
XP祭りでしか伝わらないフリップネタ #xpjug
murabayashi
0
110
Building an Out-of-Order CPU
latte72
1
720
[GoCon2026] When Goroutines Are Not Enough: Runtime Locality in High-Throughput Go
takehaya
3
540
Deep dive into the select statement (GopherCon UK)
jespino
0
170
Webの地図
yosuke_furukawa
PRO
1
230
Press start. Python's next generation.
willingc
PRO
3
320
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
100
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
200
Featured
See All Featured
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Prompt Engineering for Job Search
mfonobong
0
440
Scaling GitHub
holman
464
140k
Into the Great Unknown - MozCon
thekraken
41
2.7k
Skip the Path - Find Your Career Trail
mkilby
1
220
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.9k
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
6
1.2k
Testing 201, or: Great Expectations
jmmastey
46
8.3k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
250
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
270
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
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はデータと全く異なる型をアサーションできてしまう ◦ 気づかぬうちに大事故が起こるかも …