tRPC
/
Introduction
- What is tRPC
- Why Learn It?
- REST
- tRPC Twist
- Pros & Cons
tRPC
/
Setup
import { initTRPC } from '@trpc/server';
import { z } from 'zod';
const t = initTRPC.context<{ user?: { id: string } }>().create();
export const appRouter = t.router({
post: t.router({
getPosts: t.procedure
.input(z.object({ tag: z.string().optional() }))
.query(({ input }) => {
const posts = [
{ id: 1, title: "Hello tRPC", tag: "tech" },
{ id: 2, title: "Why TypeScript?", tag: "code" },
];
return posts.filter((p) => !input.tag || p.tag === input.tag);
}),
}),
admin: t.router({
addPost: t.procedure
.input(z.object({ title: z.string(), tag: z.string() }))
.mutation(({ input, ctx }) => {
if (!ctx.user?.id) throw new Error("Unauthorized");
return { id: Date.now(), ...input };
}),
}),
});
export type AppRouter = typeof appRouter;
tRPC
/
Client Calls
// utils/trpc.ts
import { createTRPCNext } from '@trpc/next';
import type { AppRouter } from '../server/router';
export const trpc = createTRPCNext<AppRouter>({ config: () => ({
url: '/api/trpc'
}) });
// pages/posts.tsx
import { trpc } from '../utils/trpc';
export default function Posts() {
const { data: posts } = trpc.post.getPosts.useQuery({ tag: "tech" });
return (
<ul>
{posts?.map((post) => (
<li key={post.id}>{post.title} ({post.tag})</li>
))}
</ul>
);
}
// pages/admin.tsx
import { trpc } from '../utils/trpc';
export default function AdminPanel() {
const mutation = trpc.admin.addPost.useMutation();
const handleAdd = () => mutation.mutate({ title: "New Post", tag: "news" });
return <button onClick={handleAdd}>Add Post</button>;
}
tRPC
/
Server Calls
// server/trpc.ts
import { createContext } from './context';
import { appRouter } from './router';
export const trpc = appRouter.createCaller(
await createContext({ req, res })
);
// app/api/latest.ts
import { trpc } from "server/trpc"
export default async function GET(req, res) {
const posts = await trpc.post.getPosts({ tag: "news" });
res.json(posts);
}
tRPC
/
Security
// server/trpc.ts
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.session || !ctx.session.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// infers the `session` as non-nullable
user: ctx.session.user
}
});
});
// server/router.ts
const adminRouter = t.router({
addPost: protectedProcedure
.input(z.object({ title: z.string(), tag: z.string() }))
.mutation(({ input, ctx }) => {
const newPost = { id: Date.now(), ...input };
return newPost; // In reality, save to a DB
}),
});
tRPC
/
Wrap Up