私は Alex、GitHub では "KATT" と名乗っています。tRPC というライブラリについてお話ししたいと思います。まだ記事は公開していませんが、勢いを付けるためにこの紹介記事を書いています(しかし、GitHub ではすでに 530 個以上のスターを獲得しています)。今後、記事やビデオによる紹介を予定しています!最新情報を入手したり、質問がある場合は、Twitter の @alexdotjs をフォローしてください。
簡単に言うと、tRPC は、(Node.js)サーバーからクライアントまで、型を宣言することなくエンドツーエンドの型安全性を提供します。バックエンドで行うことは、関数でデータを返すことだけで、フロントエンドではエンドポイント名に基づいてそのデータを使用します。
tRPC エンドポイントとクライアント呼び出しを行う場合、次のようになります。
優れた react-query を基盤とする React 用ライブラリ(@trpc/react
)を作成しましたが、クライアントライブラリ(@trpc/client
)は React なしでも動作します(特定の Svelte/Vue/Angular/[..]ライブラリを構築したい場合は、ご連絡ください!)
コード生成は不要で、既存の Next.js/CRA/Express プロジェクトに簡単に追加できます。
例
string
引数を取る hello
という tRPC プロシージャ(別名エンドポイント)の例を次に示します。
tsx
const appRouter = trpc.router().query('hello', {input: z.string().optional(),resolve: ({ input }) => {return {text: `hello ${input ?? 'world'}`,};},});export type AppRouter = typeof appRouter;
tsx
const appRouter = trpc.router().query('hello', {input: z.string().optional(),resolve: ({ input }) => {return {text: `hello ${input ?? 'world'}`,};},});export type AppRouter = typeof appRouter;
そして、こちらがそのデータを使用する型安全なクライアントです
tsx
import type { AppRouter } from './server';async function main() {const client = createTRPCClient<AppRouter>({url: `http://localhost:2022`,});const result = await client.query('hello', '@alexdotjs');console.log(result); // --> { text: "hello @alexdotjs" }}main();
tsx
import type { AppRouter } from './server';async function main() {const client = createTRPCClient<AppRouter>({url: `http://localhost:2022`,});const result = await client.query('hello', '@alexdotjs');console.log(result); // --> { text: "hello @alexdotjs" }}main();
型安全性を確保するために必要なのはこれだけです! result
は、バックエンドが関数で返す内容から型推論されます。入力データもバリデーターの戻り値から推論されるため、データはそのまま安全に使用できます。実際、入力データをバリデーターに渡す必要があります(tRPC は zod/yup/カスタムバリデーターとすぐに連携します)。
上記の例を試すことができる CodeSandbox リンクはこちらです:https://githubbox.com/trpc/trpc/tree/next/examples/standalone-server (プレビューではなく、ターミナル出力をご覧ください!)
え?バックエンドからクライアントにコードをインポートしているのですか? - いいえ、実際にはそうではありません
そう見えるかもしれませんが、サーバーからクライアントにコードは共有されません。TypeScript の import type
は "[..]型注釈と宣言に使用される宣言のみをインポートします。常に完全に消去されるため、実行時には残りません。" - TypeScript 3.8 で追加された機能 - TypeScript のドキュメントを参照してください。
コード生成は不要で、サーバーからクライアントに型を共有する方法があれば、今日からアプリにこれを使用できます(できればすでにモノレポを使用しているはずです)。
しかし、これはまだ始まりに過ぎません!
前述したように、React ライブラリがあり、React で上記のデータを使用する方法は次のとおりです
tsx
const { data } = trpc.useQuery(['hello', '@alexdotjs']);
tsx
const { data } = trpc.useQuery(['hello', '@alexdotjs']);
.. すると、クライアントで型安全なデータを取得できます。
既存のブラウンフィールドプロジェクト(Express/Next.js 用のアダプターがあります)で今日から tRPC を追加でき、CRA でも正常に動作し、React Native でも動作するはずです。React に限定されていないため、Svelte や Vue のライブラリを作成したい場合は、ご連絡ください。
データを変更するにはどうすればよいですか?
ミューテーションはクエリと同じくらい簡単で、実際には内部的には同じですが、構文糖として異なる方法で公開され、GET リクエストではなく HTTP POST リクエストを生成します。
データベースを使用したもう少し複雑な例を次に示します。これは、todomvc.trpc.io / https://github.com/trpc/trpc/tree/next/examples/next-prisma-todomvc の TodoMVC 例から引用しています
tsx
const todoRouter = createRouter().mutation('add', {input: z.object({id: z.string().uuid(),data: z.object({completed: z.boolean().optional(),text: z.string().min(1).optional(),}),}),async resolve({ ctx, input }) {const { id, data } = input;const todo = await ctx.task.update({where: { id },data,});return todo;},});
tsx
const todoRouter = createRouter().mutation('add', {input: z.object({id: z.string().uuid(),data: z.object({completed: z.boolean().optional(),text: z.string().min(1).optional(),}),}),async resolve({ ctx, input }) {const { id, data } = input;const todo = await ctx.task.update({where: { id },data,});return todo;},});
そして、React での使用法は次のようになります
tsx
const addTask = trpc.useMutation('todos.add');return (<><inputplaceholder="What needs to be done?"onKeyDown={(e) => {const text = e.currentTarget.value.trim();if (e.key === 'Enter' && text) {addTask.mutate({ text });e.currentTarget.value = '';}}}/></>)
tsx
const addTask = trpc.useMutation('todos.add');return (<><inputplaceholder="What needs to be done?"onKeyDown={(e) => {const text = e.currentTarget.value.trim();if (e.key === 'Enter' && text) {addTask.mutate({ text });e.currentTarget.value = '';}}}/></>)
今のところ終わりです。
とにかく、言ったように、私はただ勢いをつけたかっただけです。他にもたくさんのことがあります
- リゾルバーに依存性注入されるユーザー固有のデータの着信リクエストのコンテキストを作成する - リンク
- ルーターのミドルウェアサポート - リンク
- ルーターのマージ(すべてのバックエンドデータを 1 つのファイルにまとめたくないでしょう) - リンク
@trpc/next
アダプターを使用した、React ランドでこれまでにないほど簡単なサーバーサイドレンダリング - リンク- 型安全なエラーフォーマット - リンク
- データトランスフォーマー(ネットワーク上で Date/Map/Set オブジェクトを使用する) - リンク
- React Query のヘルパー
始めるには、Next.js の入門にいくつかの例があります。