tRPCの便利だった機能
nextと組み合わせるのをやりながら見つけた便利だった部分についての列挙
マージ機能
Routerの部分が肥大化してしまいそうだなというのが結構懸念だったが、mergeする機能があるのでこれは便利そうだった。
const appRouter = createRouter()
.merge('user.', users)
.merge('post.', posts)
Infering Types
Routerなどの各種定義からTypeScriptの型を取り出す機能。
ちょっと記述が面倒なところはあるが、AppRouter
の返り値や入力値が抽出できるので、一通り覚えておくと便利。
(とはいえinputについてはzod
のinferを利用する方がスッキリするような気もする)
Context
それぞれのrouterの処理の事前にContextを取得できるのが便利。
例えばCookieからAuthしたりなどができる。
inferについても、inferAsyncReturnType
などを利用すれば良いようだた。
ざっくり組み合わせると下記のような具合に共通化できてよかった
const createUserAppContext = (opts?: trpcNext.CreateNextContextOptions) => {
// 本来は認証など色々共通処理を行う
return {
foo: "baz"
}
}
type UserAppContext = trpc.inferAsyncReturnType<typeof createUserAppContext>
const createUserAppRouter = () => {
return trpc.router<UserAppContext>()
}
export const userRouter = createUserAppRouter()
.query( .... )
// export type definition of API
export type UserAppRouter = typeof userRouter
// export API handler
export default trpcNext.createNextApiHandler({
router: userRouter,
createContext: createUserAppContext
})
transform機能
Prismaとnext.jsを組み合わせる際、Date型が引き継げなくてsuperjson
を挟む必要が出てきたりするのだが、これもtransform
というオプションを使えばバッチリできた。
クライアント側、サーバー側どちらも設定しないと片方がズレて適切に取り出せないので注意
// サーバー側
export const appRouter = trpc.router()
.transformer(superjson)
// client側
const useUserTrpc = () => {
const client = useMemo(() => {
return createTRPCClient<UserAppRouter>({
url: '/api/trpc',
transformer: superjson,
})
}, [])
return client
}
サーバー側のエラーハンドリング
クライアントにはエラーが返ってくるが、サーバー側でもエラーをログに出すなどしたい場合は、明示的にonError
を指定しておく必要があるらしいようだった
export default trpcNext.createNextApiHandler({
router: userRouter,
createContext: createUserAppContext
onError({ error, type, path, input, ctx, req }) {
console.error(error);
}
})
もしくは`middlewareも用意されているので、こちらでエラーを出力するのでも良い可能性がある
ヘッダ送信
Clinet側からHeaderを送るにはheaders()
という関数で設定可能。
上記ドキュメントではwithTRPC
で記述されているが、vanillaなcreateTRPCClient
からでも可能
const useAuthorizedTrpc = (authToken: string) => {
return createTRPCClient<AppRouter>({
url: '/api/trpc',
headers() {
return {
Authorization: authToken
}
}
})
}
CookieやCORSなどfetch周りをいじる必要があるならfetch関数自体を変更することで対処できる模様
その他
まだあまりちゃんと触れてないがそれ以外の便利そうな部分
- middleware
- https://trpc.io/docs/middlewares
- よくあるミドルウェア機能。contextと
- メタデータ機能
- https://trpc.io/docs/metadata
- それぞれのハンドラでメタデータを設定し、middlewareなどで
- Output Validation
- https://trpc.io/docs/output-validation
- 出力についてバリデーションする機能。インターフェースを先に決めたい場合などには良いかも
- Request Batch
- https://trpc.io/docs/links
- tRPCの通信はバッチ化される。都合が悪い場合は設定でdisableにもできる
- linksの設定などを使うと更に通信周りをカスタマイズできる模様
- Subscription
- https://trpc.io/docs/subscriptions
- Websocketっぽい通信もできるっぽい(Vercelやサーバレスに乗っけてるとできないので使い所難しい)
まだ未解決な事
- クライアントサイドのコードからのコードジャンプがちょっとめんどい
- Routerの型だけ抽出できたらプロジェクト間で共有するとかできて嬉しいなと思ったが、そういうのはなさそう
- inferは充実しているのだが、router側のハンドラー定義を細かく切り出そうとするとちょっと面倒
-
CreateProcedureOptions
などProcedure
系が定義はされているが、外部で利用できるような感じにはできてなさそう
-
Discussion