原因是这样的,我想在Nestjs中创建装饰器驱动的http service
,如下所示:
@RemoteService()
export class UserRemoteService {
@Get('user/:id')
public get(@Param() id: number): Observable<UserEntity> { return null };
@Get('user/username/:username')
public getByUsername(@Param() username: string): Observable<UserEntity> { return null }
@Post('user')
public add(@Body() user: UserEntity): Observable<UserEntity> { return null };
}
我的第一个版本代码如下
export class RemoteServiceModuleOptions {
baseURL: string;
headers?: { [key: string]: any };
imports?: Array<Type<any>>;
services?: Array<Type<any>>;
}
@Module({ })
export class RemoteServiceModule {
public static forRoot(options: RemoteServiceModuleOptions): DynamicModule {
options.imports || (options.imports = []);
options.headers || (options.headers = {});
options.services || (options.services = []);
return {
module: RemoteServiceModule,
imports: [
HttpModule.register({
baseURL: options.baseURL,
}),
...options.imports,
],
providers: [
...options.services.map(Service => RemoteServiceModule.createRemoteServiceProvider(Service)),
],
exports: [
...options.services,
],
};
}
private static createRemoteServiceProvider(Service: Type<any>) {
const mappings: Map<string, any> = Reflect.getMetadata('mappings', Service);
const paramtypes: Array<any> = Reflect.getMetadata('design:paramtypes', Service) || [];
class __Service extends Service {}
return {
inject: [HttpService, ...paramtypes],
provide: Service,
useFactory: (http: HttpService, ...injects: Array<any>) => {
Array.from(mappings.entries()).forEach(([propertyKey, config]) => {
__Service.prototype[propertyKey] = function() {
const url = RemoteServiceModule.parseURL(config.url, config.params, arguments);
const data = arguments[config.body];
const method = config.method;
return http.request({ url, data, method });
};
});
return new __Service(...injects);
},
};
}
private static parseURL(url: string, params: Array<{ value: any, index: number }>, args: IArguments) {
let index = 0;
return (<string>url).replace(/:(\w+)/g, (_, param) => {
const result = (params || []).find(({ value }) => value === param);
if(result) {
return index++, args[result.index];
} else {
return args[index++];
}
});
}
}
到目前为止,一切正常,现在我想动态配置baseURL,因此我需要另一个名为RemoteServiceModule
的静态方法forRootAsync
,这样的问题是,我不能动态创建提供者,因为RemoteServiceModuleOptions
是异步的。
export interface RemoteServiceModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'> {
inject?: Array<any>;
useFactory?: (...args: Array<any>) => Promise<RemoteServiceModuleOptions> | RemoteServiceModuleOptions;
}
public static forRootAsync(options: RemoteServiceModuleAsyncOptions): DynamicModule {
options.inject || (options.inject = []);
options.imports || (options.imports = []);
return {
module: RemoteServiceModule,
imports: [...options.imports],
providers: [
{
inject: [...options.inject],
provide: RemoteServiceModuleOptions,
useFactory: options.useFactory,
},
// can not use RemoteServiceModuleOptions here
],
};
}
有什么解决办法,谢谢!