@ditsmod/trpc
Модуль @ditsmod/trpc забезпечує інтеграцію з @trpc/server. Готовий приклад застосунку з @ditsmod/trpc можна проглянути у репозиторії Ditsmod. Там ви можете знайти приклади застосування ґардів та інтерсепторів.
Швидкий старт
Ви також можете скористатись моно-репозиторієм, в якому є мінімальний код для швидкого старту:
git clone --depth 1 https://github.com/ditsmod/trpc-monorepo-starter.git
Як формуються типи для клієнта на рівні модуля
Ditsmod намагається бути прозорим для @trpc/client надаючи можливість TypeScript виводити типи зі статичного коду, без необхідності додаткової компіляції для клієнта. Кожен модуль, що надає конфігурацію для tRPC-роутера, повинен це робити у методі getRouterConfig():
import { ModuleWithTrpcRoutes, trpcRootModule } from '@ditsmod/trpc';
import { RouterOf } from '@ditsmod/trpc/client';
import { CommentModule } from './comments/comment.module.js';
import { PostController } from './post.controller.js';
// For TRPCClient
export type PostRouter = RouterOf<typeof PostModule>;
@trpcRootModule({
imports: [CommentModule],
controllers: [PostController],
})
export class PostModule implements ModuleWithTrpcRoutes {
getRouterConfig() {
return {
post: {
createPost: PostController.prototype.createPost, // Pointed to a controller
comments: CommentModule.prototype.getRouterConfig, // Pointed to a module
},
};
}
}
Тут ModuleWithTrpcRoutes - це інтерфейс, який гарантує наявність методу getRouterConfig() у даному модулі.
В даному прикладі, показано конфіг, на основі якого буде створено:
- роут
post.createPost, за який відповідатиме метод контролера -PostController.prototype.createPost; - група роутів
post.comments, за який відповідатиме імпортований модуль -CommentModule.prototype.getRouterConfig. Можна здогадатись, щоCommentModuleмає свій методgetRouterConfig(), в якому вже уточнюється які саме контролери створюють певні роути.
Зверніть увагу, що тут створюється тип PostRouter для tRPC-клієнта. Це рекомендується робити для кожного невкладеного(!) модуля, щоб пом'якшити проблеми з TypeScript-перформенсом, коли він виводить типи зі складних моделей. Але пам'ятайте, що такі типи не будуть коректно працювати для вкладених модулів. У даному прикладі CommentModule є вкладеним, тому для нього не доцільно робити export type CommentsRouter = RouterOf<typeof CommentsModule>.
Також ви можете централізовано виводити єдиний тип для змердженого tRPC-роутера на рівні застосунку, але це рекомендується робити лише у випадку, якщо у вас немає планів створювати складні моделі, аналізуючи які TypeScript буде "помирати". Щоб централізовано вивести єдиний роутер на увесь застосунок, треба скористатись AppRouterHelper:
import { trpcRootModule, type SetAppRouterOptions, type TrpcCreateOptions, type TrpcRootModule } from '@ditsmod/trpc';
import type { AppRouterHelper } from '@ditsmod/trpc/client';
import { PostModule } from '#post/post.module.js';
import { AuthModule } from '#auth/auth.module.js';
import { MessageModule } from '#message/message.module.js';
const modulesWithTrpcRoutes = [AuthModule, PostModule, MessageModule] as const;
export type AppRouter = AppRouterHelper<typeof modulesWithTrpcRoutes>;
@trpcRootModule({
imports: [...modulesWithTrpcRoutes],
})
export class AppModule implements TrpcRootModule {
setTrpcCreateOptions(): TrpcCreateOptions {
return {
// Passing options for initTRPC.create()
};
}
setAppRouterOptions(): SetAppRouterOptions {
return {
basePath: '/trpc/',
};
}
}
Зверніть увагу, що у AppRouterHelper передається не просто масив імпортованих модулів, а цей масив ще й позначено за допомогою as const - це важлива умова, без якої AppRouterHelper працюватиме некоректно.
Також зверніть увагу на інтерфейс TrpcRootModule, який вимагає обов'язкового впровадження методу setAppRouterOptions(), також опціонально можна імплементувати setTrpcCreateOptions(). Коли ваш метод setAppRouterOptions() повертає конфіг для роутера, ви не зможете передати опцію createContext, оскільки Ditsmod автоматично створює контекст у вигляді об'єкту { req, res } щоб гарантувати доступність цих змінних в контексті. Звичайно ж, в процедурах ви можете додавати будь-які інші властивості контекста.