intermediate
tRPC API boundaries
Используйте tRPC для TypeScript monorepo productivity, учитывая runtime validation, auth, deployment и public-contract limits.
tRPC разделяет TypeScript types между client и server через routers и procedures — отличная продуктивность в **monorepo** без ручной синхронизации OpenAPI.
const appRouter = router({
order: router({
byId: publicProcedure
.input(z.object({ id: z.string().uuid() }))
.query(({ input, ctx }) => ctx.orders.getById(input.id)),
create: protectedProcedure
.input(createOrderSchema)
.mutation(({ input, ctx }) => ctx.orders.create(input)),
}),
});
export type AppRouter = typeof appRouter;
Границы, которые важно соблюдать:
- **Runtime validation** (Zod) даже при static types — внешний input недоверенный.
- **Auth middleware** на procedures (`protectedProcedure`), не ad-hoc checks в handlers.
- **Public vs internal**: tRPC силён для first-party apps; third-party public API обычно нужен OpenAPI/REST для language-agnostic контрактов.
- **Deployment**: отдельные serverless functions могут требовать HTTP batching config; WebSockets для subscriptions опциональны и зависят от infra.
На интервью: когда tRPC уместен (TS full-stack команда), как дать стабильный external API рядом с tRPC, validation на границе.
Типовые ошибки: доверие compile-time types в runtime, утечка `AppRouter` types недоверенным consumers, god routers, нет дисциплины формы ошибок.
Компромисс: end-to-end TS speed против openness экосистемы — документируйте escape hatches для non-TS clients.
Чеклист:
- Zod (или аналог) на input каждой procedure.
- Auth как composable middleware.
- Отдельный public BFF от internal routers при необходимости.
- Согласованный error mapping для клиента.