Встречайте 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.

Здесь следует отметить, что наш сервер будет развернут как маршрут API Next.js. Этот код поставляется в виде пакета на стороне сервера и никак не повлияет на размер нашего клиентского пакета.

Подробнее о маршрутах 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. В этом файле мы настроим простой маршрутизатор, который действует как корень.

// 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 и присоединитесь к нашему Коллективу талантов.