Добавление процедур BFF
Роутер tRPC — контракт BFF с браузером. Устройство роутера и список процедур — в контракте, настройка транспорта — в клиенте tRPC.
Как добавить процедуру
- Согласовать имя процедуры, query/mutation, вход, результат, ошибки и необходимость авторизации.
- Если нужной операции Go нет, сначала изменить контракт в Apidog и реализацию Go, затем выполнить
bun run sync: Orval обновит клиент и схемы. Если существующих операций достаточно, новый OpenAPI не нужен. - Добавить процедуру в роутер tRPC. Для passthrough взять подходящие схемы Orval; собственный вход агрегированной процедуры описать в BFF на Zod. Hono подключает общий HTTP-адаптер (см. «Каркас»); отдельная Hono-ручка для каждой процедуры не нужна.
- В обработчике вызвать общий клиент Go, при необходимости собрать несколько ответов для интерфейса. Предметная логика остаётся в Go.
- Экспортировать
AppRouter: TypeScript выводит методы, типы входов и ответов официального клиента из роутера. Кодогенерации клиента BFF → браузер нет; независимой OpenAPI-спецификации BFF тоже нет. - Вызвать
api.<процедура>.query(...)или.mutate(...)на фронте; выполнитьtypecheckи ручную проверку результата, ошибок и авторизации.
Настройка api описана в разделе «Клиент». Например, существующая операция получения блокнота связывает сервер и клиент так:
// apps/bff/src/router/notebooks.ts
import { z } from 'zod';
import { authedProcedure, router } from '../trpc';
export const notebooks = router({
get: authedProcedure
.input(z.object({ id: z.number().int() }))
.query(({ ctx, input }) => ctx.go.getNotebook(input.id)),
});
// apps/bff/src/router/index.ts
export const appRouter = router({ auth, users, notebooks, cells });
export type AppRouter = typeof appRouter;
// apps/client: api — один раз настроенный официальный клиент из раздела «Клиент»
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server';
import type { AppRouter } from '@cdd/bff';
type NotebookInput = inferRouterInputs<AppRouter>['notebooks']['get'];
type NotebookResult = inferRouterOutputs<AppRouter>['notebooks']['get'];
const input: NotebookInput = { id: 1 };
const notebook: NotebookResult = await api.notebooks.get.query({ id: 1 });Фрагменты разных файлов; имя метода Go — по выгрузке Orval. Тип результата берётся из Go-клиента через обработчик роутера, без ручного DTO и обязательной runtime-проверки всех ответов.
Процедуры экранов
Процедура ресурса — одно действие или один ресурс. Если экрану нужно больше одного вызова Go, для него заводится процедура в роутере views: она делает вызовы Go параллельно и отдаёт один ответ. Процедуры ресурсов остаются для действий и отдельных виджетов.
Сейчас каждый экран фронта делает по одному запросу: список блокнотов — GET /notebooks, блокнот — GET /notebooks/{id}, поэтому процедур экранов пока нет.
INFO
views.notebook появится вместе с треком «Авто-VPS»: странице блокнота понадобится и сам блокнот, и статус его окружения.
// apps/bff/src/router/views.ts
export const views = router({
notebook: authedProcedure
.input(z.object({ id: z.number().int() }))
.query(async ({ ctx, input }) => {
const [notebook, runtime] = await Promise.all([ctx.go.getNotebook(input.id), ctx.go.getRuntime(input.id)]);
return { notebook, runtime };
}),
});Пример; getRuntime — будущая ручка трека «Авто-VPS».