Nest JS Part-2에서 동적 모듈 생성
Nest JS Part-2에서 동적 모듈 생성
동적 모듈에 대한 기본 개념을 얻으려면 Part-2로 이동하기 전에 이 블로그 시리즈의 Part-1을 확인하십시오. 여기 링크가 있습니다
코드 :
https://github.com/tkssharma/blogs/tree/master/nestjs-dynamic-module
이 블로그의 Part-1 일부를 마친 직후 시작합니다.
알겠습니다. Nestjs 동적 모듈로 외부 HTTP 클라이언트를 생성하는 사용 사례가 있습니다. 이 모듈은 axios 또는 httpClient와 동일한 API 호출을 수행할 수 있는 http 서비스 역할을 합니다.
이것은 데모용이며 이를 기반으로 모든 프로젝트의 어디에나 연결할 수 있는 다른 nestjs 동적 모듈을 만들 수 있습니다.
이와 같은 것을 갖는 우리의 최종 목표
동적 모듈에서 forRoot 및 forRootAsync와 같은 다양한 메서드를 모두 노출할 수 있어야 합니다.
forRootAsync
는 동적 모듈을 반환해야 합니다. HttpClientModule.forRootAsync({
imports: [AppConfigModule],
inject: [AppConfigService],
useFactory: (config: AppConfigService) => ({
apiUrl: config.platformApi.baseUrl,
apiKey: config.platformApi.apiKey,
}),
}),
시작하자
forRootAsync
및 forRoot
로 사용하려면 HttpClient 모듈이 필요합니다.우리는 HttpClientModule 옵션을 얻고 그 메소드를 사용할 서비스를 작성할 것입니다.
HttpClient 모듈의 경우 옵션은 URL 및 API 키 또는 API 호출에서 전달하려는 사용자 정의 헤더가 될 수 있습니다.
export class HttpClientService {
private readonly apiUrl: string = "";
private readonly apiKey: string = "";
constructor(
@Inject(HTTP_CLIENT_MODULE_OPTIONS)
private readonly options: HttpClientModuleOptions
) {
this.apiUrl = this.options.apiUrl;
this.apiKey = this.options.apiKey;
}
public async fetchData(method: string, payload?: any) {
return axios({
{
method,
url: `${this.apiUrl}/health`,
data,
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.apiKey}`,
}
}
);
}
}
export const HTTP_CLIENT_MODULE_OPTIONS = "HttpClientModuleOptions";
export const HTTP_CLIENT_TOKEN = "HttpClientToken";
export const HTTP_CLIENT_MODULE = "HttpClientModule";
공급자를 사용
HttpClientModuleOptions
하고 반환할 수 있는 공급자를 만듭니다. 공급자는 주입 가능한 토큰 HTTP_CLIENT_TOKEN을 사용하고 해당 주입 가능한 토큰의 값은 HttpClientService 서비스의 인스턴스입니다.export function createHttpClientProvider(
options: HttpClientModuleOptions
): Provider {
return {
provide: HTTP_CLIENT_TOKEN,
useValue: getHttpClientModuleOptions(options),
};
}
export const getHttpClientModuleOptions = (
options: HttpClientModuleOptions
): HttpClientService => new HttpClientService(options);
이제 공급자를 추가하기 위해 HttpClientModule에서 이
createHttpClientProvider
함수를 사용할 수 있습니다.다음은 두 메서드 모두에 대한 정적 메서드인 Root 및 forRootAsync를 만드는 중요한 부분입니다.
구조와 같은 모듈을 반환해야 합니다.
{
module: HttpClientModule,
imports: options.imports,
providers: [...this.createAsyncProviders(options), provider],
exports: [provider],
}
@Global()
@Module({})
export class HttpClientModule {
public static forRoot(options: HttpClientModuleOptions): DynamicModule {
const provider: Provider = createHttpClientProvider(options);
return {
module: HttpClientModule,
providers: [provider],
exports: [provider],
};
}
public static forRootAsync(
options: HttpClientModuleAsyncOptions
): DynamicModule {
const provider: Provider = {
inject: [HTTP_CLIENT_MODULE_OPTIONS],
provide: HTTP_CLIENT_TOKEN,
useFactory: async (options: HttpClientModuleOptions) =>
getHttpClientModuleOptions(options),
};
return {
module: HttpClientModule,
imports: options.imports,
providers: [...this.createAsyncProviders(options), provider],
exports: [provider],
};
}
private static createAsyncProviders(
options: HttpClientModuleAsyncOptions
): Provider[] {
if (options.useExisting || options.useFactory) {
return [this.createAsyncOptionsProvider(options)];
}
const useClass = options.useClass as Type<HttpClientModuleFactory>;
return [
this.createAsyncOptionsProvider(options),
{
provide: useClass,
useClass,
},
];
}
private static createAsyncOptionsProvider(
options: HttpClientModuleAsyncOptions
): Provider {
if (options.useFactory) {
return {
provide: HTTP_CLIENT_MODULE_OPTIONS,
useFactory: options.useFactory,
inject: options.inject || [],
};
}
const inject = [
(options.useClass ||
options.useExisting) as Type<HttpClientModuleFactory>,
];
return {
provide: HTTP_CLIENT_MODULE_OPTIONS,
useFactory: async (optionsFactory: HttpClientModuleFactory) =>
await optionsFactory.createHttpModuleOptions(),
inject,
};
}
}
forRoot 구현을 디코딩할 수 있습니다. 여기에서 우리는 DynamicModule을 반환하고 있으며 createHttpClientProvider에서 반환된 공급자를 사용하여 이를 내보내고 있습니다. createHttpClientProvider는 httpClientService의 인스턴스일 뿐입니다.
public static forRoot(options: HttpClientModuleOptions): DynamicModule {
const provider: Provider = createHttpClientProvider(options);
return {
module: HttpClientModule,
providers: [provider],
exports: [provider],
};
}
// createHttpClientProvider will return this
{
provide: HTTP_CLIENT_TOKEN,
useValue: new HttpClientService(options)
}
비동기식 옵션 제공자의 다양한 형태
비동기 공급자
때때로 애플리케이션 시작은 하나 이상의 비동기 작업이 완료될 때까지 지연되어야 합니다. 예를 들어 데이터베이스와의 연결이 설정될 때까지 요청 수락을 시작하지 않으려는 경우가 있습니다. 비동기 공급자를 사용하여 이를 달성할 수 있습니다.
https://docs.nestjs.com/fundamentals/custom-providers
useClass
@Module({
imports: [
HttpClientModule.forRootAsync({ useClass: ConfigService})
]
})
useFactory
@Module({
imports: [HttpClientModule.forRootAsync({
useFactory: () => {
return {
host: "localhost",
port: 5432,
database: "nest",
user: "john",
password: "password"
}
}
})]
})
사용기존
@Module({
imports: [HttpClientModule.registerAsync({
useExisting: ConfigService
})]
})
다중 비동기 옵션 공급자 기술 지원
우리는 홈 스트레치에 있습니다. 이제 위에서 설명한 추가 기술을 지원하기 위해 forRootAsync() 메서드를 일반화하고 최적화하는 데 중점을 둘 것입니다. 완료되면 모듈은 세 가지 기술을 모두 지원합니다.
이 모든 경우에 대한 코드를 확인해 보겠습니다.
public static forRootAsync(
options: HttpClientModuleAsyncOptions
): DynamicModule {
const provider: Provider = {
inject: [HTTP_CLIENT_MODULE_OPTIONS],
provide: HTTP_CLIENT_TOKEN,
useFactory: async (options: HttpClientModuleOptions) =>
getHttpClientModuleOptions(options),
};
return {
module: HttpClientModule,
imports: options.imports,
providers: [...this.createAsyncProviders(options), provider],
exports: [provider],
};
}
이제 우리가 알고 있듯이 옵션 개체는 이러한 다른 유형일 수 있으므로 처리해야 합니다.
private static createAsyncProviders(
options: HttpClientModuleAsyncOptions
): Provider[] {
if (options.useExisting || options.useFactory) {
return [this.createAsyncOptionsProvider(options)];
}
const useClass = options.useClass as Type<HttpClientModuleFactory>;
return [
this.createAsyncOptionsProvider(options),
{
provide: useClass,
useClass,
},
];
}
모든 이름 옵션이 있는 HttpClientModuleAsyncOptions도 살펴보겠습니다.
export interface HttpClientModuleOptions {
apiUrl: string;
apiKey: string;
}
export interface HttpClientModuleFactory {
createHttpModuleOptions: () =>
| Promise<HttpClientModuleOptions>
| HttpClientModuleOptions;
}
export interface HttpClientModuleAsyncOptions
extends Pick<ModuleMetadata, "imports"> {
inject?: any[];
useClass?: Type<HttpClientModuleFactory>;
useExisting?: Type<HttpClientModuleFactory>;
useFactory?: (
...args: any[]
) => Promise<HttpClientModuleOptions> | HttpClientModuleOptions;
}
이러한 모든 준비가 완료되면 이 모듈을 다음과 같이 다양한 방식으로 사용할 수 있습니다.
HttpClientModule.forRootAsync({
imports: [AppConfigModule],
inject: [AppConfigService],
useFactory: (config: AppConfigService) => ({
apiUrl: config.platformApi.baseUrl,
apiKey: config.platformApi.apiKey,
}),
})
다른 옵션
@Module({
imports: [HttpClientModule.forRootAsync({
useExisting: AppConfigService
})]
})
We could expect a dynamic module to be constructed with the following properties:
{
module: HttpClientModule,
imports: [],
providers: [
{
provide: HTTP_CLIENT_MODULE_OPTIONS,
useFactory: async (optionsFactory: HttpClientModuleFactory) =>
await optionsFactory.createHttpModuleOptions(),
inject,
},
],
}
결론
패턴은 @nestjs/jwt, @nestjs/passport 및 @nestjs/typeorm과 같은 모든 인기 있는 모듈에서 사용됩니다. 이제 이러한 패턴이 얼마나 강력한지 뿐만 아니라 자신의 프로젝트에서 어떻게 사용할 수 있는지 알게 되기를 바랍니다.
참조
Reference
이 문제에 관하여(Nest JS Part-2에서 동적 모듈 생성), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/tkssharma/creating-dynamic-modules-in-nest-js-part-2-g1j텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)