リンクの概要
リンクを使用すると、tRPCクライアントとサーバー間のデータの流れをカスタマイズできます。リンクは、tRPC操作(クエリ、ミューテーション、またはサブスクリプション)に対する自己完結型の変更、または操作に基づく副作用(ロギングなど)のいずれか1つだけを行う必要があります。
リンクをまとめて配列に構成し、links
プロパティを介してtRPCクライアント構成に提供できます。これはリンクチェーンを表します。つまり、tRPCクライアントはリクエストの実行時にlinks
配列に追加された順にリンクを実行し、応答の処理時に逆順に再度実行します。以下は、リンクチェーンの視覚的な表現です。
以下の例はNext.jsを使用していることを前提としていますが、下記と同じものがvanilla tRPCクライアントを使用している場合に追加できます。
utils/trpc.tstsx
import { httpBatchLink, loggerLink } from '@trpc/client';import { createTRPCNext } from '@trpc/next';export default createTRPCNext<AppRouter>({config() {const url = `http://localhost:3000`;return {links: [loggerLink(),httpBatchLink({url,}),],};},});
utils/trpc.tstsx
import { httpBatchLink, loggerLink } from '@trpc/client';import { createTRPCNext } from '@trpc/next';export default createTRPCNext<AppRouter>({config() {const url = `http://localhost:3000`;return {links: [loggerLink(),httpBatchLink({url,}),],};},});
カスタムリンクの作成
リンクは、TRPCLink
タイプに従う関数です。各リンクは3つの部分で構成されています。
- リンクは、
TRPCClientRuntime
型のパラメータを持つ関数を返します。この引数はtRPCによって渡され、終端リンクを作成するときに使用されます。終端リンクを作成しない場合は、パラメータなしの関数を作成できます。この場合、リンクは呼び出さずにlinks
配列に追加する必要があります(links: [..., myLink, httpBatchLink(...)]
)。 - ステップ1の関数は、2つのプロパティを持つオブジェクトを受け取る別の関数を返します。1つはクライアントによって実行されている
Operation
であるop
、もう1つはチェーンの次のリンクを呼び出すために使用する関数であるnext
です。 - ステップ2の関数は、
@trpc/server
によって提供されるobservable
関数を返す最終的な関数を返します。observable
は、リンクがチェーンの次のリンクに操作結果の処理方法を通知するのに役立つobserver
を受け取る関数を受け入れます。この関数では、next(op)
を返すか、next
をサブスクライブして、リンクが操作結果を処理できるようにすることができます。
例
utils/customLink.tstsx
import { TRPCLink } from '@trpc/client';import { observable } from '@trpc/server/observable';import type { AppRouter } from 'server/routers/_app';export const customLink: TRPCLink<AppRouter> = () => {// here we just got initialized in the app - this happens once per app// useful for storing cache for instancereturn ({ next, op }) => {// this is when passing the result to the next link// each link needs to return an observable which propagates resultsreturn observable((observer) => {console.log('performing operation:', op);const unsubscribe = next(op).subscribe({next(value) {console.log('we received value', value);observer.next(value);},error(err) {console.log('we received error', err);observer.error(err);},complete() {observer.complete();},});return unsubscribe;});};};
utils/customLink.tstsx
import { TRPCLink } from '@trpc/client';import { observable } from '@trpc/server/observable';import type { AppRouter } from 'server/routers/_app';export const customLink: TRPCLink<AppRouter> = () => {// here we just got initialized in the app - this happens once per app// useful for storing cache for instancereturn ({ next, op }) => {// this is when passing the result to the next link// each link needs to return an observable which propagates resultsreturn observable((observer) => {console.log('performing operation:', op);const unsubscribe = next(op).subscribe({next(value) {console.log('we received value', value);observer.next(value);},error(err) {console.log('we received error', err);observer.error(err);},complete() {observer.complete();},});return unsubscribe;});};};
参考文献
カスタムリンクの作成に関してより現実的な参照が必要な場合は、GitHubでtRPCが提供する組み込みリンクのいくつかを確認できます。
終端リンク
終端リンクは、リンクチェーンの最後のリンクです。next
関数を呼び出す代わりに、終端リンクは構成されたtRPC操作をtRPCサーバーに送信し、OperationResultEnvelope
を返す役割を担います。
tRPCクライアント構成に追加するlinks
配列には、少なくとも1つのリンクが含まれている必要があり、そのリンクは終端リンクである必要があります。links
の最後に終端リンクがない場合、tRPC操作はtRPCサーバーに送信されません。
httpBatchLink
は、tRPCで推奨される終端リンクです。
httpLink
およびwsLink
は、終端リンクの他の例です。
コンテキストの管理
操作がリンクチェーンに沿って移動すると、各リンクが読み取りおよび変更できるコンテキストが維持されます。これにより、リンクは他のリンクが実行ロジックで使用するメタデータをチェーンに沿って渡すことができます。
op.context
にアクセスして、現在のコンテキストオブジェクトを取得し、変更します。
query
またはuseQuery
フック(またはmutation
、subscription
など)にコンテキストパラメータを提供することで、特定の操作のコンテキストオブジェクトの初期値を設定できます。
使用例については、特定の要求のバッチ処理を無効にするを参照してください。