ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Nest.js] 15 - Configuration
    Nest.js 2021. 9. 22. 02:25

    Contents
    1. Configuration?
    2. Codebase vs Environment Variables
    3. Module Installation
    4. Configuration implementation


    1. Configuration?

    - In our source code, some of codes that we have written may be affected by Application Environment, Development Environment, or be protected from others.

    - Therefore, we will deal with those code to save in much securer way, which is called Configuration File.

    - Configuration files are not usually changed during runtime, these are loaded and defined when an application starts.

    - It could be a XML, JSON, YAML, or Environment Variables type.

    - let's start to manage and protect our configuration information.


    2. Codebase vs Environment Variables

     

    Codebase

    - Usually, Codebase configuration files have information, which is OK to be exposed, such as Port number.

    - XML, JASON, or YAML are Codebase configuration file.

     

    Environment Variables

    - It is much focused on secure informtaion of application, such as API key, or password.


    3. Module Installation

    Window only

    $ npm install -g win-node-env

     

    and then, Window & MAC OS

    $ npm install config --save

    4. Configuration Implementation

     

    1. create a config directory to manage all configuration files.

     

    2. create 3 YAML(YML) files

     

    3. cofig/default.yaml

    server:
      port: 3000
    
    db:
      type: 'mysql'
      port: 3306
      database: 'test'
    
    jwt:
      expiresIn: 3600

     

    4. config/development.yml => default.yml + information in Development environment

    db:
      host: 'localhost'
      username: 'root'
      password: '1234'
      synchronize: true
    
    jwt:
      secret: 'Secret1234'

     

    5. config/production.yml => => default.yml + information in Production environment

    db:
      synchronize: false

     

    6. src/main.ts

    ...
    import * as config from 'config'; // 1
    
    async function bootstrap() {
      const logger = new Logger();
      const app = await NestFactory.create(AppModule);
    
      const serverConfig = config.get('server'); // 2
      const port = serverConfig.port; // 3
    
      // Global Pipe
      ...
    
      // const port = 3000; // 4
      await app.listen(port);
    
      Logger.log(`Application running on port ${port}`);
      logger.log(`Application running on port ${port}`);
    }
    bootstrap();

    // 1. import all files in config directory.

    // 2. config.get('server') - search a scope, which is named as 'server'.

    // 3. serverConfig.port - read the Key, which is named as 'port', and then return its value.

    // 4. now we manage port number in configuration file, default.yaml.

     

    7.1 src/configs/typeorm.config.ts : before using configuration files

    import { TypeOrmModuleOptions } from '@nestjs/typeorm';
    
    export const TypeORMConfig: TypeOrmModuleOptions = {
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: '1234',
      database: 'test',
      entities: [__dirname + '/../**/*.entity.{js,ts}'],
      synchronize: true,
    };

    // this file exposes all secure information directly, even though I put this path in .gitignore

    // let's change this with configuration file.

     

    7.2 src/configs/typeorm.config.ts : after using configuration files

    import { TypeOrmModuleOptions } from '@nestjs/typeorm';
    import * as config from 'config';
    
    const dbConfig = config.get('db'); // 1
    
    export const TypeORMConfig: TypeOrmModuleOptions = {
      type: dbConfig.type, // 2
      host: process.env.RDS_HOSTNAME || dbConfig.host, // 3
      port: process.env.RDS_PORT || dbConfig.port, // 2
      username: process.env.RDS_USERNAME || dbConfig.username, // 3
      password: process.env.RDS_PASSWORD || dbConfig.password, // 3
      database: process.env.RDS_DB_NAME || dbConfig.database, // 2
      entities: [__dirname + '/../**/*.entity.{js,ts}'],
      synchronize: dbConfig.synchronize, // 4
    };

    ### process.env.XXX are not defined yet, it will apply if process.env.XXX exists in a real server environment

    // 1. load a scope, named as 'db', thus default.yaml, development.yml, and production.yml are all loaded to the variable.

    // 2. those key and value are defined in default.yaml

    // 3. those key ans value are defined in development.yml

    // 4. dbConfig.synchronize - are defined in both development.yml and production.yml,
            so we can easily change based on running environment.

     

    8. src/auth/auth.module.ts

    ...
    import * as config from 'config';
    
    const jwtConfig = config.get('jwt'); // 1
    
    @Module({
      imports: [
        PassportModule.register({ defaultStrategy: 'jwt' }),
        JwtModule.register({
          secret: process.env.JWT_SECRET || jwtConfig.secret, // 2
          signOptions: {
            expiresIn: jwtConfig.expiresIn, // 3
          },
        }),
        TypeOrmModule.forFeature([UserRepository]),
      ],
      controllers: [AuthController],
      providers: [AuthService, JwtStrategy],
      exports: [JwtStrategy, PassportModule],
    })
    export class AuthModule {}

    // 1. load a scope, named as 'jwt', thus default.yaml, and development.yml are all loaded to the variable.

    // 2. process.env.JWT_SECRET - look for a key first in a server, if not found, use development.yml's value

    // 3. this key and value is defined in defualt.yaml

     

    // 9. src/auth/jwt.strategy.ts

    ...
    import * as config from 'config';
    
    @Injectable()
    export class JwtStrategy extends PassportStrategy(Strategy) {
      constructor(
        @InjectRepository(UserRepository)
        private userRepository: UserRepository
      ) {
          super({
            secretOrKey: process.env.JWT_SECRET || config.get('jwt.secret'), // 1
            jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
          })
      }
      
      
      ...
    }

    // 1. config.get('jwt.secret') - use directly scope('jwt'), key('secret') and value('Secret1234') from config directory.

     

     

     

     

Designed by Tistory.