Запознайте се с tRPC: инструмент за изграждане на API с цялостна типова безопасност.

Когато за първи път започнах да разработвам приложения с пълен стек, изграждах и управлявах свои собствени REST API. Започнах да ги създавам в Java със Spring, след това преминах към .NET, след това към Node.js с Express и дори се занимавах малко с Django. Да се ​​каже, че управлението на два различни проекта на различни езици (понякога) е тромаво, би било леко казано.

Въведете tRPC, инструмент за изграждане на API с цялостна типова безопасност. tRPC ви позволява да създавате стабилни и мащабируеми бек-ендове за вашите приложения Next.js, React и Node.js много бързо.

Събудих ли интереса ви? Тогава ви насърчавам да продължите да четете! В тази статия ще разгледаме какво е tRPC и как можете да го настроите и използвате с Next.js.

Какво е tRPC?

Както споменах преди, tRPC ви позволява да създавате напълно безопасни API за вашите приложения Next.js, React и Node.js. С неговата безопасност от край до край вие сте в състояние да улавяте грешки между предния и задния край по време на компилиране, вместо по време на изпълнение. И тъй като използвате само декларации за типове и не импортирате действителен сървърен код, компилациите ви остават малки и бързи.

Инсталиране на tRPC

Инсталирането на tRPC е доста лесно. Има няколко пакета, от които се нуждаем, както от самия tRPC, така и от два други, които ще направят живота ни много по-лесен. Във вашия проект Next.js изпълнете следната команда, за да инсталирате вашите зависимости.

$ yarn add @trpc/client @trpc/server @trpc/react @trpc/next zod react-query

tRPC е изграден върху `react-query`, който е пакет за извличане, кеширане и управление на данни, без да е необходимо да се забърквате с което и да е глобално състояние. Ние също използваме `zod`, за да помогнем с нашата схема и проверки на входа.

Следващото нещо, което трябва да направим, е да се уверим, че строгият режим е активиран в нашия `tsconfig.json`

json
// tsconfig.json
{
 // …
 “compilerOptions”: {
 // …
 “strict”: true
 }
}

Това не е специално за tRPC, а по-скоро за правилното изпълнение на `zod`. Конкретно `zod` също не е изискване за използване на tRPC, но, както ще видите по-късно, работи много добре с него и прави живота ни много по-лесен.

Създаване на нашия сървър

В корена на нашия проект или в папката „/src“, ако използвате Next.js с това, създайте нова папка, наречена „/server“. Тази папка ще съдържа нашия tRPC контекст, рутер и действителните ни API маршрути.

Едно нещо, което трябва да се отбележи тук е, че нашият сървър ще бъде разгърнат като Next.js API маршрут. Този код се доставя като пакет от страна на сървъра и по никакъв начин няма да повлияе на размерите на нашите клиентски пакети.

Можете да прочетете повече за маршрутите на API на Next.js в [Документите на Next.js](https://nextjs.org/docs/api-routes/introduction)

Конфигуриране на нашия контекст

Първото нещо, което искаме да създадем тук, е нашият контекст. Нашият контекст ни позволява да предаваме данни за заявка на всеки от нашите резолвери в нашите маршрути. За да създадем нов контекст, нека създадем файл, наречен „context.ts“ и да добавим следния код към него.

// server/context.ts
import { CreateNextContextOptions } from “@trpc/server/adapters/next”;
import { inferAsyncReturnType } from “@trpc/server”;
export async function createContext(contextOptions?: CreateNextContextOptions) {
 const req = contextOptions?.req;
 const res = contextOptions?.res;
return {
 req,
 res,
 };
}
export type MyContextType = inferAsyncReturnType<typeof createContext>;

Тук просто предаваме заявката и отговора на нашите маршрути. Можете да добавите и други неща, които искате да предадете тук. Неща като Prisma клиенти и NextAuth сесии са добри примери за това.

Създаване на прост рутер

След това нека да продължим и да добавим файл „create-router.ts“. В този файл ще настроим прост рутер, който действа като root.

// server/create-router.ts
import * as trpc from “@trpc/server”;
import { MyContextType } from “./context”;
export function createRouter() {
 return trpc.router<MyContextType>();
}

Декларирането на вашите рутери по този начин е невероятно полезно, тъй като ви позволява да добавите персонализирана логика на междинния софтуер към всички маршрути, които използват вашия рутер. Например, можете да създадете рутер, който проверява дали даден потребител е влязъл или дали потребителят има правилните разрешения за достъп до ресурс.

Конфигуриране на нашите API маршрути

Нека създадем нова папка, наречена „маршрутизатори“ и да добавим два файла към нея. Първо добавете файл, наречен `_app.ts`. Този файл ще действа като наш основен маршрут. Всички нови маршрути, които добавим, ще бъдат добавени тук.

// server/routers/_app.ts
import { createRouter } from “../create-router”;
export const appRouter = createRouter();
export type AppRouter = typeof appRouter;

След това нека създадем нашия втори файл и да го наречем `nameRouter.ts`. Този рутер ще вземе име и ще го върне на клиента.

// server/routers/nameRouter.ts
import { z } from “zod”;
import { createRouter } from “../create-router”;
export const nameRouter = createRouter.query(“getName”, {
  input: z.object({
  name: z.string().nullish(),
 }),
 resolve({ input }) {
  return { greeting: `Hello ${input.name}!` };
 },
});

tRPC използва заявки и мутации, за да дефинира действия. Заявката се използва за извличане на данни, а мутациите се използват за създаване, актуализиране и изтриване на данни. В кода по-горе създаваме заявка за получаване на име. Нашата заявка приема два параметъра. Първото е името на заявката, а второто са нашите параметри. За нашите параметри имаме вход и разрешаване. Въвеждането не е задължително, докато се изисква разрешаване. Resolve е действителното внедряване на нашата крайна точка. В нашия случай използваме Zod, за да проверим дали имаме входен низ и нашата крайна точка ще върне низ, който казва „здравей“ на каквото и да е име, което подаваме.

Вече можем да се върнем обратно към „_app.ts“ и да добавим нашия маршрут там.

// server/routers/_app.ts
// […]
import { nameRouter } from “./nameRouter”;
export const appRouter = createRouter().merge(“names.”, nameRouter);
// […]

Добавяне на крайна точка в Next.js

Трябва да добавим нова крайна точка в Next.js. Под папката `/pages/api` създайте нов файл под `/trpc/[trpc].ts`. Структурата на вашата папка трябва да изглежда така:

.
+ — pages
| + — api
| + — trpc
  | + — [trpc].ts

Сега добавете следния код към `[trpc].ts`:

// pages/api/trpc/[trpc].ts
import { createNextApiHandler } from “@trpc/server/adapters/next”;
import { appRouter } from “../../../server/routers/_app”;
import { createContext } from “../../../server/context”;
export default createNextApiHandler({
  router: appRouter,
  createContext,
  batching: {
  enabled: true,
 },
});

Сега можем да настроим нашия преден край!

Извикване на нашите API маршрути

Свързването на нашия бек-енд с нашия преден край е много лесно. Първо, трябва да преминем към нашия файл `_app.tsx` и да конфигурираме tRPC и React Query. За да направим това, отиваме към компонента от по-висок ред `withTrpc()`.

// pages/_app.tsx
// […]
import { withTRPC } from “@trpc/next”;
import { AppRouter } from “./api/trpc/[trpc]”;
function getBaseUrl() {
 if (process.browser) return “”;
 if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;
return `http://localhost:${process.env.PORT ?? 3000}`;
}
export default withTRPC<AppRouter>({
 config({ ctx }) {
 const url = `${getBaseUrl()}/api/trpc`;
 return {
   url,
  };
 },
 ssr: true,
})(MyApp);

След това трябва да добавим нова папка, наречена utils, и да добавим файл, наречен „trpc.ts“.

// utils/trpc.ts
import { createReactQueryHooks } from “@trpc/react”;
import { AppRouter } from “../server/routers/_app”;
import { inferProcedureOutput } from “@trpc/server”;

Тук създаваме нашата кука за използване на tRPC на клиента. Куката е строго типизирана с помощта на подписа на типа на нашия API. Това е „магията“, която ни дава нашата цялостна типова безопасност. Тази кука ни позволява да извикаме нашия бек-енд и да получим напълно въведени входове и изходи от него. И ако промените име на маршрут, ще получите грешка на клиента. Много е мощен.

Последното нещо, което трябва да направим, е всъщност да използваме нашата заявка. Създайте нова страница и я наименувайте `name.tsx`. Добавете следния код към него

// pages/name.tsx
import { trpc } from “../utils/trpc”;
export default function Name() {
 const nameQuery = trpc.useQuery([“name.getName”, { name: “Brock” }]);
return (
  <>
   {nameQuery.data ? (
    <h1>{nameQuery.data.greeting}</h1>
   ) : (
    <span>Loading…</span>
   )}
  </>
 );
}

Разбира се, не се колебайте да замените „Брок“ с вашето име!

Нека да стартираме нашето приложение Next.js и да преминем към нашата нова страница. На страницата „/name“ вече трябва да видите съобщение, което казва „Здравей“ на каквото и да е име, което сте въвели.

Заключение

В тази статия разгледахме какво е tRPC и как да го използваме с приложение Next.js. tRPC прави изграждането на API за вашите приложения невероятно лесно. Можете не само да го използвате с Next.js, но също така можете да го използвате и с React и Node.js приложения. За повече информация вижте [tRPC документите](https://trpc.io/). Можете също така да намерите различни примери на страницата [Примерни приложения](https://trpc.io/docs/example-apps), включително стартово приложение за Next.js и React Native.

Приятно кодиране на всички!

Повече съдържание в PlainEnglish.io. Регистрирайте се за нашия безплатен седмичен бюлетин. Следвайте ни в Twitter и LinkedIn. Вижте нашия Community Discord и се присъединете към нашия Talent Collective.