Open10
tRPC メモ
これの通りにやります
backend routerを定義する
- router instanceを作成する
- query procedureを追加する
- mutation procedureを追加する
Procedures
バックエンド関数を作成するための非常に柔軟なプリミティブです。ビルダパターンを使用しているので、バックエンドアプリケーションの様々な部分に対して再利用可能なベースプロシージャを作成することができます。プロシージャはRESTエンドポイントや関数と同等と見なすことができます。
以下2つのエンドポイントを持つことを想定
userById(id: string) => { id: string; name: string; }.
userCreate(data: { name: string }) => { id: string; name: string; }.
router instanceを作成する
server.ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create();
const router = t.router;
const publicProcedure = t.procedure;
const appRouter = router({});
// Export type router type signature,
// NOT the router itself.
export type AppRouter = typeof appRouter;
query procedureを追加する
server.ts
// @filename: server.ts
import { initTRPC } from '@trpc/server';
const t = initTRPC.create();
interface User {
id: string;
name: string;
}
const userList: User[] = [
{
id: '1',
name: 'KATT',
},
];
const appRouter = t.router({
userById: t.procedure
.input((val: unknown) => {
if (typeof val === 'string') return val;
throw new Error(`Invalid input: ${typeof val}`);
})
.query(({ input }) => {
const user = userList.find((u) => u.id === input);
return user;
}),
});
export type AppRouter = typeof appRouter;
mutation procedureを追加する
server.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
const t = initTRPC.create();
const router = t.router;
const publicProcedure = t.procedure;
interface User {
id: string;
name: string;
}
const userList: User[] = [
{
id: '1',
name: 'KATT',
},
];
const appRouter = router({
userById: publicProcedure
.input((val: unknown) => {
if (typeof val === 'string') return val;
throw new Error(`Invalid input: ${typeof val}`);
})
.query((req) => {
const input = req.input;
const user = userList.find((it) => it.id === input);
return user;
}),
userCreate: publicProcedure
.input(z.object({ name: z.string() }))
.mutation((req) => {
const id = `${Math.random()}`;
const user: User = {
id,
name: req.input.name,
};
userList.push(user);
return user;
}),
});
export type AppRouter = typeof appRouter;
クライアントで使用する
- tRPCクライアントを設定する
- Querying & mutating
tRPCクライアントを設定する
client.ts
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './server';
// Notice the <AppRouter> generic here.
const trpc = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:3000/trpc',
}),
],
});
Querying & mutating
これで、trpc オブジェクトの API プロシージャにアクセスできるようになりました。試してみてください。
client.ts
// Inferred types
const user = await trpc.userById.query('1');
const createdUser = await trpc.userCreate.mutate({ name: 'sachinraja' });
Intellisenseを開いて、フロントエンドでAPIを探索することができます。プロシージャのルートと、それを呼び出すためのメソッドがすべて表示されます。
@trpc/server
Proceduresについて
インプットバリデーションなし
import { router, publicProcedure } from './trpc';
import { z } from 'zod';
const appRouter = router({
// Create publicProcedure at path 'hello'
hello: publicProcedure.query(() => {
return {
greeting: 'hello world',
};
}),
});
インプットバリデーションあり with Zod
Zodでバックエンドが API に適合したリクエストのみを処理することを保証する
import { publicProcedure, router } from './trpc';
import { z } from 'zod';
export const appRouter = router({
hello: publicProcedure
.input(
z
.object({
text: z.string(),
})
.optional(),
)
.query(({ input }) => {
return {
greeting: `hello ${input?.text ?? 'world'}`,
};
}),
});
export type AppRouter = typeof appRouter;
publicProcedureとprotectedProcedure
Procedure実行前にユーザーにログインを強いるミドルウェアを使用しているのがprotectedProcedure
複数のインプットパーサー
複数のProcedures
再利用可能なBase Procedures
コンテキスト
コンテキストは、すべてのtRPCプロシージャがアクセスできるデータを保持し、データベース接続や認証情報のようなものを置くのに最適な場所です。コンテキストの設定は、初期化時に型を定義し、リクエストごとに実行時コンテキストを作成する2ステップで行われます。
コンテキストの型を定義する
コンテキストを作成する
イナーコンテキストとアウターコンテキスト
ミドルウェア
t.procedure.use()メソッドで、プロシージャにミドルウェアを追加することができる。
Authorization
実行前にユーザーが「admin」であることを確認します。
Logging
クエリーのタイミングが自動的に記録されます。
Context Swapping
ミドルウェアがコンテキストのプロパティを変更し、プロシージャが新しいコンテキスト値を受け取る