Jump to content

Attention: This page is 25 days older than the English version and might be outdated. If you're a native speaker of this language and would like to contribute to the project, please consider updating this page to match the latest English version.

You can also view the English version of this page.

tRPC

ุชุณู…ุญ ู„ูƒ tRPC ุจูƒุชุงุจุฉ type safe api ุฏููˆู† ุงู„ุญูŽุงุฌุฉ ุฅู„ู‰ ุชูŽูˆู„ูŠุฏ ูƒูˆุฏ ูุชูู†ุญูŠ ุนู†ูƒ ุญูŽุฏูˆุซ ุฃุฎุทุงุก ู…ูุงุฌุฆุฉ ุฃุซู†ุงุก ุงู„ู€ runtimeุŒ ุญูŠุซ ุฅู†ู‡ุง ุชูŽุณุชุบู„ ุฎุงุตูŠุฉ ุงู„ู€ inference ููŠ Typescript ุญุชู‰ ุชุถู…ู† ุงู„ู€ type safety ุนูู†ุฏ ู†ุฏุงุก ุงู„ู€ Api ู…ู† ุงู„ู€ Frontend

I built tRPC to allow people to move faster by removing the need of a traditional API-layer, while still having confidence that our apps won't break as we rapidly iterate.

Avatar of @alexdotjs
Alex - creator of tRPC @alexdotjs

Files

ู„ุณูˆุก ุงู„ุญุธ ูุฅู† tRPC ุชุชุทู„ุจ ู‚ู„ูŠู„ุงู‹ ู…ู† ุงู„ู€ boilerplate ูˆู„ูƒู† ู„ุญุณู† ุงู„ุญุธ ูุงู† create-t3-app ุชุญู…ู„ ุนู†ูƒ ู‡ุฐุง ุงู„ุนุจุก.

๐Ÿ“„ ู…ู„ู pages/api/trpc/[trpc].ts

ู‡ุฐุฉ ู‡ูŠ ู†ู‚ุทุฉ ุฏุฎูˆู„ูƒ ุงู„ูŠ tRPC ApiุŒ ููŠ ุงู„ุฃูˆุถุงุน ุงู„ุทุจูŠุนูŠุฉ ู„ู† ุชุญุชุงุฌ ุงู„ูŠ ุฃู† ุชูŽู…ุณ ู‡ุฐุง ุงู„ู…ู„ู ูƒุซูŠุฑุง. ููŠู…ูƒู†ูƒ ุชุบูŠูŠุฑู‡ ุนู†ุฏ ุชูุนูŠู„ CORS Middleware ุงูˆ ุดุฆ ู…ู† ู‡ุฐุง ุงู„ู‚ุจูŠู„ ูˆูŠู‚ูˆู… ุจุนู…ู„ export ู„ู€ createNextHandler Next.js API handlerโ†— ูˆุงู„ุฐูŠ ูŠู‚ุจู„ requestโ†— ูˆ responseโ†—

ู…ู…ุง ูŠุนู†ูŠ ุฃู†ูƒ ู‚ุงุฏุฑ ุนู„ู‰ ุงุณุชุฎุฏุงู… createNextApiHandler ููŠ ุฃูŠ middleware ุชุฑูŠุฏู‡ุŒ ุฅู‚ุฑุฃ example snippet

ู…ู„ู ๐Ÿ“„ server/trpc/context.ts

ููŠ ู‡ุฐุง ุงู„ู…ู„ู ุชู‚ูˆู… ุจุงู†ุดุงุก ุงู„ู€ Context ุงู„ุชูŠ ุณูŠุชู… ุชู…ุฑูŠุฑู‡ ุงู„ูŠ tRPC Procedure ุŒ ุงู„ู€ Context ู‡ูˆ ุนุจุงุฑุฉ ุนู† ุงู„ุจูŠุงู†ุงุช ุงู„ุชูŠ ุณูŠูƒูˆู† ู„ูƒู„ ุงู„ู€ Procedures ูˆุตูˆู„ ู„ู‡ุง ูˆู‡ูŠ ู…ูƒุงู† ู…ูู†ุงุณุจ ู„ุชุถุน ุฃุดูŠุงุก ู…ุซู„ database connections ูˆู…ุนู„ูˆู…ุงุช ุงู„ู…ุตุงุฏู‚ุฉ ูˆุบูŠุฑู‡ุง.

  • ู…ุง ู‡ูˆ createContextInner: ู‡ูู†ุง ุชูŽู‚ูˆู… ุจุฅู†ุดุงุก ุงู„ู€ Context ุงู„ุฐูŠ ู„ุง ูŠูŽุนุชู…ุฏ ุนูŽู„ู‰ ุงู„ู€ request ู…ูุซู„ ุฅุชุตุงู„ ู‚ุงุนุฏุฉ ุงู„ุจูŠุงู†ุงุช. ูˆูŠู…ูƒู†ูƒ ุฅุณุชุฎุฏุงู… function ู„ู€ integration testing ุงูˆ ssg-helpersโ†—
  • ู…ุง ู‡ูˆ createContext ุŸ ู‡ูู†ุง ุญูŽูŠุซ ุชูŽู‚ูˆู… ุจุฅู†ุดุงุก ุงู„ู€ Context ุงู„ุฐูŠ ูŠุนุชู…ุฏ ุนู„ู‰ ุงู„ู€ request ููŠู…ูƒู†ูƒ ุงู„ูˆุตูˆู„ ุงู„ู‰ ุงู„ู€ req Object ุนู† ุทุฑูŠู‚ opts.req ูˆู…ู† ุซูู… ุชูŽู…ุฑูŠุฑุฉ ุงู„ูŠ createContextInnerู„ุฅู†ุดุงุก ุงู„ู€ Context ุงู„ู†ู‡ุงุฆูŠ

๐Ÿ“„ู…ู„ู server/trpc/trpc.ts

ููŠ ู‡ุฐุง ุญูŽูŠุซู ูŠู…ูƒู†ูƒ ุชุญุฏูŠุฏ ุงู„ู€ proceduresโ†— ูˆ middlewaresโ†—ุŒ ู…ู† ุงู„ุงูุถู„ ุงู† ู„ุง ุชู‚ูˆู… ุจุนู…ู„ export ู„ู€ t Object ูƒุงู…ู„ุง /middlewares) ุจู„ ู‚ู… ุจุชุตุฏูŠุฑ procedures ูˆ middlewares ุณุชู„ุงุญุธ ุฃู†ู†ุง ู†ุณุชุฎุฏู… superjson ูƒู€ data transformerโ†—ุŒ ุฐู„ูƒ ุญุชู‰ ู†ุญูุธ ุงู„ู€ Types ู„ุญูŠู† ุฅุณุชุฎุฏุงู…ู‡ุง ููŠ ููŠ ุงู„ู€ clientุŒ ูู…ุซู„ุง ุฅุฐุง ูƒุงู† ุงู„ู€ Type ู‡ูˆ Date ูุฅู† ุงู„ู€ client ุณูŽูŠูุนูŠุฏ Date ,gds string

๐Ÿ“„ ู…ู„ู server/trpc/router/*.ts

ู‡ู†ุง ูŠู…ูƒู†ูƒ ุชุญุฏูŠุฏ ุงู„ู€ route ,ูˆุงู„ู€ procedure ู„ู„ู€ APIุŒ ู…ู† ุงู„ุงูุถู„ ุฃู† ุชูู†ุดุฆ routersโ†— ู…ูู†ูุตู„ุฉ ู„ู„ู€ procedures ุงู„ู…ุชู‚ุงุฑุจุฉ ูˆู…ู† ุซูŽู… ุฏู…ุฌู‡ุงโ†— ููŠ router ูˆุงุญุฏ ููŠ server/trpc/router/_app.ts

๐Ÿ“„ ู…ู„ู utils/trpc.ts

ู‡ุฐู‡ ู‡ูŠ ู†ู‚ุทุฉ ุฏุฎูˆู„ ุงู„ูˆุงุฌู‡ุฉ ุงู„ุฃู…ุงู…ูŠุฉ ู„ู€ tRPC. ู‡ุฐุง ู‡ูˆ ุงู„ู…ูƒุงู† ุงู„ุฐูŠ ุณุชู‚ูˆู… ููŠู‡ ุจุงุณุชูŠุฑุงุฏ type definition ุงู„ุฎุงุต ุจุงู„ู€ procedure ูˆุฅู†ุดุงุก tRPC client ุงู„ุฎุงุต ุจูƒ ุฌู†ุจู‹ุง ุฅู„ู‰ ุฌู†ุจ ู…ุน react query hooks. ู†ุธุฑู‹ุง ู„ุฃู†ู†ุง ู‚ู…ู†ุง ุจุชูุนูŠู„ โ€œsuperjsonโ€ ููŠ ุงู„ูˆุงุฌู‡ุฉ ุงู„ุฎู„ููŠุฉ ูู†ุญู† ุจุญุงุฌุฉ ุฅู„ู‰ ุชูุนูŠู„ุฉ ุนู„ู‰ ุงู„ูˆุงุฌู‡ุฉ ุงู„ุฃู…ุงู…ูŠุฉ ุฃูŠุถู‹ุง. ู‡ุฐุง ู„ุงู† ุงู„ุจูŠุงู†ุงุช ุงู„ุชูŠ ูŠุญุฏุซ ู„ู‡ุง serialized ููŠ ุงู„ู€ client ูŠุชู… ุนู…ู„ deserialized ู„ู‡ุง ููŠ ุงู„ู€ client.

ู‡ู†ุง ุชู‚ูˆู… ุจุชุญุฏูŠุฏ ุฑูˆุงุจุทโ†— ุงู„ู€ tRPC ุญูŠุซ ุชููุญุฏุฏ ุงู„ู…ุณุงุฑ ุงู„ุฐูŠ ุณูŠู…ุฑ ุจู‡ ุงู„ู€ request ู…ู† ุงู„ู€ client ุฅู„ู‰ ุงู„ู€ server ู†ุญู† ู†ุณุชุฎุฏู… httpBatchLinkโ†— ุจุดูƒู„ ุฅูุชุฑุงุถูŠ ู…ุน ุชูุนูŠู„ request batchingโ†— ูˆ loggerLinkโ†—

ูˆููŠ ุงู„ุงุฎูŠุฑ ู†ู‚ูˆู… ุจุชุตุฏูŠุฑ helper typeโ†— ุญุชู‰ ู†ุณุชุนู…ู„ ุงู„ู€ type infre ููŠ ุงู„ู€ frontend

ูƒูŠู ุฃุณุชุฎุฏู… tRPC ุŸ

ู†ู†ุตุญูƒ ุจู…ุดุงู‡ุฏุฉ ู‡ุฐุงa killer talk at Next.js Confโ†— ู…ู† trashh_devโ†—

ู…ุน tRPCุชูƒุชุจ Function ููŠ ุงู„ู€ backend ูˆุงู„ุชูŠ ูŠู…ูƒู† ู…ู†ุงุฏุงุชู‡ุง ู…ู† ุงู„ู€ frontend

server/trpc/router/user.ts
const userRouter = t.router({
  getById: t.procedure.input(z.string()).query(({ ctx, input }) => {
    return ctx.prisma.user.findFirst({
      where: {
        id: input,
      },
    });
  }),
});

ููŠ ู†ู‡ุงูŠุฉ ุงู„ุฃู…ุฑ ุชุชุญูˆู„ tRPC procedure ุงู„ูŠ backend ุนุงุฏูŠ ููŠู‚ูˆู… ุจูุญุต ุงู„ู€ input ูˆูŠู…ุฑุฑ ุงู„ู€ request ุฅุฐุง ูƒุงู† ุตุญูŠุญุงู‹ูˆูŠุนูŠุฏ ุฑุณุงู„ุฉ ุฎุทุฃ ุฅุฐุง ูƒุงู†ุช ุงู„ู…ุฏุฎู„ุงุช ุบูŠุฑ ุตุญูŠุญุฉ. ุจุนุฏ ุงู„ุชุฃูƒุฏ ู…ู† ุตุญุฉ ุงู„ุจูŠุงู†ุงุช ูŠุชู… ู†ุฏุงุก function ูˆุงู„ุชูŠ ุฅู…ุง ู„ุฌู„ุจ ุจูŠุงู†ุงุช (queryโ†—) ุฃูˆ ุฃู† ุชุบูŠุฑ ููŠ ุงู„ุจุงู†ุงุช (mutationโ†—) ุฃู†ุช

server/trpc/router/_app.ts
const appRouter = t.router({
  users: userRouter,
  posts: postRouter,
  messages: messageRouter,
});

export type AppRouter = typeof appRouter;

ู„ุงุญุธ ุฃู†ู†ุง ู†ู‚ูˆู… ุจุนู…ู„ export ูู‚ุท ู„ู€ routerโ€™s type ุฃูŠ ุฃู†ู†ุง ู„ุง ู†ุณุชุฎุฏู… ุงูŠ ู…ู† ุงู„ู€ server code ููŠ ุงู„ู€ client ุงู„ุงู† ุฏุนู†ุง ู†ู†ุงุฏูŠ ุงู„ู€ procedure ู…ู† ุงู„ู€ frontend ุŒ tRPC ุชูˆูุฑ wrapper ู„ู…ูƒุชุจุฉ @tanstack/react-query ู…ู…ุง ูŠุณู…ุญ ู„ูƒ ุจุฅุณุชุฎุฏุงู… ุงู„ู…ูƒุชุจุฉ ุจูƒุงู…ู„ ู‚ูˆุชู‡ุง.

pages/users/[id].tsx
import { useRouter } from "next/router";

const UserPage = () => {
  const { query } = useRouter();
  const userQuery = trpc.user.getById.useQuery(query.id);

  return (
    <div>
      <h1>{userQuery.data?.name}</h1>
    </div>
  );
};

ุณุชู„ุงุญุธ ุนู„ู‰ ุงู„ููˆุฑ ู…ุฏู‰ ุฌูˆุฏุฉ ุงู„ุฅูƒู…ุงู„ ุงู„ุชู„ู‚ุงุฆูŠ ูˆุงู„ู€ typesafety. ุจู…ุฌุฑุฏ ูƒุชุงุจุฉ โ€œtrpc.โ€ ุŒ ุณุชุธู‡ุฑ router ุงู„ุฎุงุตุฉ ุจูƒ ููŠ ุงู„ุฅูƒู…ุงู„ ุงู„ุชู„ู‚ุงุฆูŠ ุŒ ูˆุนู†ุฏู…ุง ุชุญุฏุฏ ุงู„ู€ routerุŒ ุณุชุธู‡ุฑ ุงู„ู€ procedures. ูˆุณุชุญุตู„ ุฃูŠุถู‹ุง ุนู„ู‰ ุฎุทุฃ TypeScript ุฅุฐุง ูƒุงู†ุช ุงู„ู…ูุฏุฎู„ุงุช ุงู„ุฎุงุต ุจูƒ ู„ุง ูŠุชุทุงุจู‚ ู…ุน ุงู„ู€ schema ุงู„ุฐูŠ ุญุฏุฏุชู‡ ู…ุณุจู‚ุง.

ูƒูŠู ุงูู†ุงุฏูŠ API ุฎุงุฑุฌูŠ ุŸ

ุจุงุณุชุฎุฏุงู… ุงู„ู€ API ุงู„ุนุงุฏูŠุฉ ุŒ ูŠู…ูƒู†ูƒ ุงุณุชุฏุนุงุก ุงู„ู€ End point ุงู„ุฎุงุตุฉ ุจูƒ ุจุงุณุชุฎุฏุงู… ุฃูŠ ุนู…ูŠู„ HTTP ู…ุซู„ curl ุฃูˆ Postman ุฃูˆ fetch ุฃูˆ ู…ุจุงุดุฑุฉ ู…ู† ู…ุชุตูุญูƒ. ู…ุน tRPC ุŒ ุงู„ุฃู…ุฑ ู…ุฎุชู„ู ุจุนุถ ุงู„ุดูŠุก. ุฅุฐุง ูƒู†ุช ุชุฑุบุจ ููŠ ุงู„ุงุชุตุงู„ ุจุงู„ู€ procedure ุจุฏูˆู† ุนู…ูŠู„ tRPC ุŒ ูู‡ู†ุงูƒ ุทุฑูŠู‚ุชุงู† ู…ูˆุตู‰ ุจู‡ู…ุง ู„ู„ู‚ูŠุงู… ุจุฐู„ูƒ:

Expose a single procedure externally

ุฅุฐุง ุฃุฑุฏุช ุฃู† ุชูุชูŠุญ procedure ู„ู„ู€ Apis ุงู„ุฎุงุฑุฌูŠุฉ ุงู„ู‚ ู†ุธุฑุฉ ุนู„ูŠ server side callsโ†—ุŒ ู…ู…ุง ุณูŠุณู…ุญ ู„ูƒ ุจุนู…ู„ Next.js Api ุฅุนุชูŠุงุฏูŠุฉ

pages/api/users/[id].ts
import { type NextApiRequest, type NextApiResponse } from "next";
import { appRouter } from "../../../server/trpc/router/_app";
import { createContext } from "../../../server/trpc/context";

const userByIdHandler = async (req: NextApiRequest, res: NextApiResponse) => {
  // Create context and caller
  const ctx = await createContext({ req, res });
  const caller = appRouter.createCaller(ctx);
  try {
    const { id } = req.query;
    const user = await caller.user.getById(id);
    res.status(200).json(user);
  } catch (cause) {
    if (cause instanceof TRPCError) {
      // An error from tRPC occured
      const httpCode = getHTTPStatusCodeFromError(cause);
      return res.status(httpCode).json(cause);
    }
    // Another error occured
    console.error(cause);
    res.status(500).json({ message: "Internal server error" });
  }
};

export default userByIdHandler;

ุชุญูˆู„ ูƒู„ ุงู„ู€ Procedures ุงู„ูŠ REST endpoint ุŸ

ุฅุฐุง ูƒู†ุช ุชุฑุบุจ ููŠ ูƒุดู ูƒู„ ุงู„ู€ ุ›ู‚ุฎุคุซูŠุนู‚ุซุณ ุŒ ุงู„ู‚ ู†ุธุฑุฉ ุนู„ูŠ trpc-openapiโ†—.

Itโ€™s just HTTP Requests

tRPC communicates over HTTP, so it is also possible to call your tRPC procedures using โ€œregularโ€ HTTP requests. However, the syntax can be cumbersome due to the RPC protocolโ†— that tRPC uses. If youโ€™re curious, you can check what tRPC requests and responses look like in your browserโ€™s network tab, but we suggest doing this only as an educational exercise and sticking to one of the solutions outlined above.

Comparison to a Next.js API endpoint

ุฏุนู†ุง ู†ู‚ุงุฑู† โ€ Next.js Endpointโ€ ุจู€ โ€œtRPC procedureโ€. ู„ู†ูุชุฑุถ ุฃู†ู†ุง ู†ุฑูŠุฏ ุฌู„ุจ โ€œObjectโ€ ู…ุณุชุฎุฏู… ู…ุนูŠู† ู…ู† ู‚ุงุนุฏุฉ ุจูŠุงู†ุงุชู†ุง ูˆุฅุนุงุฏุชู‡ ุฅู„ู‰ ุงู„ูˆุงุฌู‡ุฉ ุงู„ุฃู…ุงู…ูŠุฉ. ูŠู…ูƒู†ู†ุง ูƒุชุงุจุฉ Next.js API Endpoint ู…ุซู„ ู‡ุฐุง:

pages/api/users/[id].ts
import { type NextApiRequest, type NextApiResponse } from "next";
import { prisma } from "../../../server/db/client";

const userByIdHandler = async (req: NextApiRequest, res: NextApiResponse) => {
  if (req.method !== "GET") {
    return res.status(405).end();
  }

  const { id } = req.query;

  if (!id || typeof id !== "string") {
    return res.status(400).json({ error: "Invalid id" });
  }

  const examples = await prisma.example.findFirst({
    where: {
      id,
    },
  });

  res.status(200).json(examples);
};

export default userByIdHandler;
pages/users/[id].tsx
import { useState, useEffect } from "react";
import { useRouter } from "next/router";

const UserPage = () => {
  const router = useRouter();
  const { id } = router.query;

  const [user, setUser] = useState(null);
  useEffect(() => {
    fetch(`/api/user/${id}`)
      .then((res) => res.json())
      .then((data) => setUser(data));
  }, [id]);
};

ู‚ุงุฑู† ู‡ุฐุง ุจู…ุซุงู„ tRPC ุฃุนู„ุงู‡ ูˆูŠู…ูƒู†ูƒ ุฑุคูŠุฉ ุจุนุถ ู…ุฒุงูŠุง tRPC:

  • ุจุฏู„ุงู‹ ู…ู† ุชุญุฏูŠุฏ ุนู†ูˆุงู† url ู„ูƒู„ ู…ุณุงุฑ ุŒ ูˆุงู„ุฐูŠ ูŠู…ูƒู† ุฃู† ูŠุตุจุญ ู…ุฒุนุฌู‹ุง ุฅุฐุง ุญุงูˆู„ุช ู†ู‚ู„ ุดูŠุก ู…ุง ุŒ ูุฅู† ุงู„ู€ router ุจุฃูƒู…ู„ู‡ ุนุจุงุฑุฉ ุนู† Object ู…ุน ุงู„ุฅูƒู…ุงู„ ุงู„ุชู„ู‚ุงุฆูŠ.
  • ู„ุณุช ุจุญุงุฌุฉ ุฅู„ู‰ ุงู„ุชุญู‚ู‚ ู…ู† HTTP method ุงู„ุชูŠ ุชู… ุงุณุชุฎุฏุงู…ู‡ุง.
  • ู„ุง ุชุญุชุงุฌ ุฅู„ู‰ ุงู„ุชุญู‚ู‚ ู…ู† ุฃู† ุงู„ุทู„ุจ ุฃูˆ ุงู„ู€ query ุŒ ู„ุฃู† Zod ูŠุนุชู†ูŠ ุจุฐู„ูƒ.
  • ุจุฏู„ุงู‹ ู…ู† ุฅู†ุดุงุก ุงู„ู€ responde object ุŒ ูŠู…ูƒู†ูƒ ุฅุฑุฌุงุน ุฃุฎุทุงุก ุงูˆ ู‚ูŠู…ุฉ ุฃูˆ Object ูƒู…ุง ุชูุนู„ ููŠ ุฃูŠ function.

snippets ู…ููŠุฏุฉ

ุชูุนูŠู„ CORS

pages/api/trpc/[trpc].ts
import { type NextApiRequest, type NextApiResponse } from "next";
import { createNextApiHandler } from "@trpc/server/adapters/next";
import { appRouter } from "~/server/trpc/router/_app";
import { createContext } from "~/server/trpc/context";
import cors from "nextjs-cors";

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  // Enable cors
  await cors(req, res);

  // Create and call the tRPC handler
  return createNextApiHandler({
    router: appRouter,
    createContext,
  })(req, res);
};

export default handler;

Optimistic updates

ุงู„ู€ Optimistic updates ู‡ูŠ ุชุญุฏูŠุซุงุช ุชุญุฏูŠุซ ูˆุงุฌู‡ุฉ ุงู„ู…ุณุชุฎุฏู… ู‚ุจู„ ุฃู† ูŠู†ุชู‡ูŠ ุงู„ู€ Request ู…ู…ุง ูŠูุญุณู† ุชุฌุฑุจุฉ ุงู„ู…ุณุชุฎุฏู…ุŒ ู„ูƒู† ุงู„ุชุทุจูŠู‚ุงุช ุงู„ุชูŠ ุชููุถู„ ุฏู‚ุฉ ุงู„ู…ุนู„ูˆู…ุงุช ูŠุฌุจ ุฃู† ุชุชุฌู†ุจ ุงู„ู€ Optimistic updatesุŒ ู„ู„ู…ุฒูŠุฏ ู…ู† ุงู„ู…ุนู„ูˆู…ุงุช ุฅู‚ุฑุง React Query docsโ†—.

const MyComponent = () => {
  const listPostQuery = trpc.post.list.useQuery();

  const utils = trpc.useContext();
  const postCreate = trpc.post.create.useMutation({
    async onMutate(newPost) {
      // Cancel outgoing fetches (so they don't overwrite our optimistic update)
      await utils.post.list.cancel();

      // Get the data from the queryCache
      const prevData = utils.post.list.getData();

      // Optimistically update the data with our new post
      utils.post.list.setData(undefined, (old) => [...old, newPost]);

      // Return the previous data so we can revert if something goes wrong
      return { prevData };
    },
    onError(err, newPost, ctx) {
      // If the mutation fails, use the context-value from onMutate
      utils.post.list.setData(undefined, ctx.prevData);
    },
    onSettled() {
      // Sync with server once mutation has settled
      utils.post.list.invalidate();
    },
  });
};

ุนูŠู†ุฉ ู…ู† Integration Test

ุฅู‚ุฑุฃ Vitestโ†—

import { type inferProcedureInput } from "@trpc/server";
import { createContextInner } from "~/server/router/context";
import { appRouter, type AppRouter } from "~/server/router/_app";
import { expect, test } from "vitest";

test("example router", async () => {
  const ctx = await createContextInner({ session: null });
  const caller = appRouter.createCaller(ctx);

  type Input = inferProcedureInput<AppRouter["example"]["hello"]>;
  const input: Input = {
    text: "test",
  };

  const example = await caller.example.hello(input);

  expect(example).toMatchObject({ greeting: "Hello test" });
});

Useful Resources

ResourceLink
tRPC Docshttps://www.trpc.ioโ†—
Bunch of tRPC Exampleshttps://github.com/trpc/trpc/tree/next/examplesโ†—
React Query Docshttps://tanstack.com/query/v4/docs/adapters/react-queryโ†—

Recent Contributors To This Page