繁体   English   中英

在 NestJS 模块中使用配置服务的最佳实践

[英]Best practice to use config service in NestJS Module

我想使用环境变量来配置每个模块的HttpModule ,从文档中我可以使用这样的配置:

@Module({
  imports: [HttpModule.register({
    timeout: 5000,
    maxRedirects: 5,
  })],
})

但是我不知道从环境 vairable(或配置服务)中包含 baseURL 的最佳做法是什么,例如:

@Module({
imports: [HttpModule.register({
    baseURL:  this.config.get('API_BASE_URL'),
    timeout: 5000,
    maxRedirects: 5,
})],

this.config在这里undefined ,因为它不在课堂上。

从环境变量(或配置服务)设置 baseURL 的最佳做法是什么?

1月19日更新

HttpModule.registerAsync()是在 5.5.0 版本中添加的,带有这个pull request

HttpModule.registerAsync({
  imports:[ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    baseURL:  configService.get('API_BASE_URL'),
    timeout: 5000,
    maxRedirects: 5,
  }),
  inject: [ConfigService]
}),

原帖

这个问题在这个问题上进行了讨论。 对于像TypeOrmModuleMongooseModule这样的 nestjs 模块,实现了以下模式。

useFactory方法返回配置对象。

TypeOrmModule.forRootAsync({
  imports:[ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    type: configService.getDatabase()
  }),
  inject: [ConfigService]
}),

虽然卡米尔写道

上述约定现在适用于所有嵌套模块,并将被视为最佳实践(+对第 3 方模块的推荐)。 更多在文档中

它似乎还没有为HttpModule实现,但也许你可以打开一个关于它的问题。 我上面提到的问题中还有一些其他的建议。

还可以查看官方文档,了解如何实现ConfigService的最佳实践。

尽管对于大多数实现来说,这个问题的最高评价答案在技术上是正确的,但@nestjs/typeorm包和TypeOrmModule的用户应该使用看起来更像下面的实现。

// NestJS expects database types to match a type listed in TypeOrmModuleOptions
import { TypeOrmModuleOptions } from '@nestjs/typeorm/dist/interfaces/typeorm-options.interface';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
      load: [mySettingsFactory],
    }),
    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        type: configService.get<TypeOrmModuleOptions>('database.type', {
          infer: true, // We also need to infer the type of the database.type variable to make userFactory happy
        }),
        database: configService.get<string>('database.host'),
        entities: [__dirname + '/**/*.entity{.ts,.js}'],
        synchronize: true,
        logging: true,
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [],
})
export class AppRoot {
  constructor(private connection: Connection) {}
}

这段代码所做的主要事情是从 TypeORM 中检索正确的类型(参见导入)并使用它们来提示返回值 configService.get() 方法。 如果你不使用正确的 TypeORM 类型,Typescript 会发疯的。

我还遇到了实现ConfigService的几个问题,如 NestJS 文档中所述(没有类型安全性,没有配置值的模块化,...),我在这里非常详细地写下了我们公司的最终 NestJS 配置管理策略: NestJS 配置管理

基本思想是有一个中央配置模块,从进程环境中加载所有配置值。 但是,不是为所有模块提供单一服务,而是每个模块都可以注入配置值的专用子集! 因此,每个模块都包含一个类,该类指定该模块在运行时需要提供的所有配置值。 这同时为开发人员提供了对配置值的类型安全访问(而不是在整个代码库中使用字符串文字)

希望这种模式也适用于您的用例:)

@Kim Kern的好回答,它清楚地将ConfigService注入模块配置,这可能依赖于环境变量; 然而,根据我的个人经验,你的 app-root 模块或一些其他带有几个导入的模块可能会变得拥挤和/或难以阅读以及理解导入、模块配置和你定义的模块所依赖的内容。 因此,感谢Jay McDoniel为我策划了这个问题, you can move configuration logic into a separate file中。



第一个解决方案


app.module.ts示例:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MikroOrmModule } from '@mikro-orm/nestjs';

import { AppService } from './users.service';
import { AppController } from './users.controller';
import { get_db_config } from './config/database.config';

@Module({
    imports:     [
        ConfigModule.forRoot({ 
            isGlobal:        true, 
            expandVariables: true,
        }),

        MikroOrmModule.forRootAsync( get_db_config() ),
    ],
    controllers: [AppController],
    providers:   [AppService],
})
export class AppModule {}

config/database.config.ts示例:

import { MikroOrmModuleAsyncOptions } from "@mikro-orm/nestjs";
import { ConfigService } from "@nestjs/config";


export function get_db_config(): MikroOrmModuleAsyncOptions
{
    return {
        useFactory: (configService: ConfigService) => 
        ({
            dbName:          'driver',
            type:            'postgresql',
            host:             configService.get('DB_HOST'),
            port:             configService.get('DB_PORT'),
            user:             configService.get('DB_USERNAME'),
            password:         configService.get('DB_PASSWORD'),
            autoLoadEntities: true
        }),
        inject: [ConfigService]
    }
}



但是, NestJS Docs - Configuration Namespaces以及 NestJS Authentication and Authorization Course 提供了解决此问题的替代方法。



第二种解决方案


auth.module.ts示例:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';

import jwtConfig from './jwt.config';


@Module({
    imports: [
        ConfigModule.forFeature( jwtConfig ),
        JwtModule.registerAsync( jwtConfig.asProvider() ),
    ]
})
export class AuthModule {}

jwt.config.ts示例:

import { registerAs } from "@nestjs/config"


export default registerAs('jwt', () => {
    return {
        secret:         process.env.JWT_SECRET,
        issuer:         process.env.JWT_TOKEN_ISSUER,
        accessTokenTtl: parseInt(process.env.JWT_TOKEN_TTL)
    };
});

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM