Nestjs ํ™˜๊ฒฝ๋ณ€์ˆ˜ (env) ์„ค์ • ๋ฐ ์‚ฌ์šฉ

2023. 7. 29. 19:15ใ†Study_Develop/์ธํ”„๋Ÿฐ - Slack ํด๋ก ์ฝ”๋”ฉ(๋ฐฑ์—”๋“œ)

๋ฐ˜์‘ํ˜•

Nestjs ํ™˜๊ฒฝ๋ณ€์ˆ˜ (env) ์„ค์ • ๋ฐ ์‚ฌ์šฉ

 

๊ฐ•์‚ฌ๋‹˜์ด ๊ฐ•์˜ ์ค‘ ๋‹ค๋Œ๋ธŒ ๋‹ค๋Œ๋ธŒ ๋ผ๊ณ  ๋ง์”€ํ•˜์‹œ๊ธธ๋ž˜

env๋ฅผ ์™œ ๋‹ค๋Œ๋ธŒ๋ผ๊ณ  ๋ถ€๋ฅด์‹œ์ง€? ์‹ถ์—ˆ๋Š”๋ฐ

dotenv = .env

์š”๊ฑฐ ์˜€๋‹น ใ…‹

 

 

dotenv๋ž€?

 

์šฐ์„  env๋ž€, ์œ ๋‹‰์Šค ๋ฐ ์œ ๋‹‰์Šค ๊ณ„์—ด ์šด์˜ ์ฒด์ œ์šฉ ์…€ ๋ช…๋ น์–ด์ด๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜์˜ ๋ชฉ๋ก์„ ์ถœ๋ ฅํ•˜๊ฑฐ๋‚˜, ํ˜„์กดํ•˜๋Š” ํ™˜๊ฒฝ์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ๋ณ€๊ฒฝ๋œ ํ™˜๊ฒฝ ๋‚ด์—์„œ ๋‹ค๋ฅธ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์‹คํ–‰ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. env๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ธฐ์กด ๋ณ€์ˆ˜๋Š” ์ƒˆ๋กœ์šด ๊ฐ’์„ ์ด๋“ค์— ํ• ๋‹นํ•จ์œผ๋กœ์จ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

 

dotenv๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ .env๋ผ๋Š” ํŒŒ์ผ์— ์ €์žฅํ•˜๊ณ  

process.env๋กœ ๋กœ๋“œํ•˜๋Š” ์˜์กด์„ฑ ๋ชจ๋“ˆ์ด๋‹ค.

 

์ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋กœ๋Š” ๊ฐœ๋ฐœ๊ณผ์ •์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ณ ์œ ํ•œ api key๊ฐ’ ๋“ฑ ๋ฏผ๊ฐํ•œ ์ •๋ณด์˜ ๋ณด์•ˆ์„ ์œ„ํ•ด์„œ์ด๋‹ค.

๋งŒ์•ฝ, ๊นƒํ—ˆ๋ธŒ ๊ฐ™์ด ์˜คํ”ˆ์†Œ์Šค์— ๊ณต๊ฐœ๋„๋ฆฌ ๊ฒฝ์šฐ์—” ํ•ดํ‚น์„ ๋‹นํ•  ์œ„ํ—˜์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฏผ๊ฐํ•œ ์ •๋ณด์˜ ๊ฒฝ์šฐ์—” .env๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

 

 

1. ํŒจํ‚ค์ง€ ์„ค์น˜

 

$ npm i --save @nestjs/config

 

-> ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•ด config ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•œ๋‹ค.

 

2. ConfigModule์„ค์ •

 

import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [ConfigModule.forRoot()],
})

 

- ์„ค์น˜ํ•œ configํŒจํ‚ค์ง€ ์„ค์ •์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

 

- AppModule์—์„œ ์ง์ ‘ import ํ•ด๋„ ์ƒ๊ด€ ์—†๋Š”๋ฐ, ConfigModule์„ค์ • ๋ถ€๋ถ„์ด ์ฝ”๋“œ๊ฐ€ ๋งŽ์•„์ง€๋Š” ๊ฒฝ์šฐ, APpModule์ด ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜๋„ ์žˆ์–ด ๋ณ„๋„์˜๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ณ  ConfigurationModule ์„ ๋งŒ๋“ค์–ด์„œ AppModule์—์„œ import ํ•˜๋„๋ก ์„ค์ •ํ–ˆ๋‹ค.

 

3. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ •์˜

 

.env>

SECRET = ์ œ๋กœ์ดˆ๋ฐ”๋ณด
PORT = 3030

 

- ํ”„๋กœ์ ํŠธ a-nest ํด๋”์— .envํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ , ์œ„์™€ ๊ฐ™์ด ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

- ๋ณ„๋„์˜ ์˜ต์…˜์„ ๋ช…์‹œํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ, envํŒŒ์ผ์— ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋‹ค๊ณ  ์•”๋ฌต์ ์œผ๋กœ ์•ฝ์†์ด ๋˜์–ด ์žˆ๋‹ค.

 

- ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ฐธ์กฐํ•  ํŒŒ์ผ path๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์œผ๋ฉด envFilePath์˜ต์…˜์œผ๋กœ ์„ค์ •์„ ๋ฐ”๊พธ๋ฉด ๋œ๋‹ค.

 

 

4. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์‚ฌ์šฉ

 

 

app.module.ts>

 

@Get() 
  getHello(){
    return this.appService.getHello();
  }

 

app.service.ts>

 

@Injectable()
export class AppService {
  async getHello() {
    return process.env.SECRET;
  }
}

 

 

process.env๋ง๊ณ , @nestjs/config๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ด์œ 

 

dotenv๋งŒ ์“ฐ๋ฉด ๋˜์ง€ @nest/config๋ฅผ ์™œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‚˜์š”??

 

nest์™€ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” ์ตœ์†Œํ•œ test/dev/prod ์„ธ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ

๊ฐ ํ™˜๊ฒฝ๋งˆ๋‹ค ๋‹ค๋ฅธ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

์˜ˆ์ „์ฒ˜๋Ÿผ dev/prod ๋‹จ ๋‘ ํ™˜๊ฒฝ๋งŒ ์žˆ์—ˆ๋‹ค๋ฉด ์–ด๋А ํ™˜๊ฒฝ์ธ์ง€ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ฒดํฌํ•˜๊ธฐ๋งŒ ํ–ˆ์–ด๋„ ๋˜์—ˆ์ง€๋งŒ 

์ด์ œ๋Š” ์ ์ฐจ ํ™˜๊ฒฝ์ด ๋ถ„ํ™”๋˜๊ณ  ์žˆ๊ธฐ์— @nestjs/config๋ฅผ ํ†ตํ•ด์„œ ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์— ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

๋ฌผ๋ก , nest ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ์„œ๋„ ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์— ์ ํ•ฉํ•œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

 

if (process.env.NODE_ENV === 'production') {
    module.exports = require('./prod');
} else if (process.env.NODE_ENV === 'testing') {
    module.exports = require('./test');
} else {
    module.exports = require('./dev');
}

 

์š”๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ๋ณ„๋„์˜ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ  requireํ•˜๋Š” ๋ฐฉ์‹๋„ ์žˆ๋‹ค.

 

but, ํ˜„์žฌ nest ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ด์šฉํ•ด ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, 

๊ตณ์ด ์ด๋Ÿฐ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

 

๋˜ํ•œ ์˜์กด์„ฑ ์ฃผ์ž…ํ•  ๋•Œ, ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ฐ’์„ ์ž์œ ์ž์žฌ๋กœ ์‚ฌ์šฉ๊ฐ€๋Šฅ!

 

 

๋”ฐ๋ผ์„œ!

 

service.ts>

    return process.env.SECRET;

 

process.env๋ฅผ ์ง์ ‘ ๊ฐ€์ ธ๋‹ค๊ฐ€ ์“ฐ๊ธฐ๋ณด๋‹ค๋Š”, 

์ด๊ฒƒ๋งˆ์ €๋„ configService์— ์“ฐ๋Š”๊ฒŒ ์ข‹์Œ!

 

service.ts>

@Injectable()
export class AppService {
  constructor (private readonly configService: ConfigService){
  }

  getHello() : string {
    return this.configService.get('DB_PASSWORD');
    //process.env.DB_PASSWORD
  }
}

 

์š”๋Ÿฐ ๋ฐฉ์‹!

 

DB_PASSWORD ์ •๋ณด๋Š” .env์•ˆ์— ์žˆ๋‹ค.

 

- process.env ๋Œ€์‹  ConfigService๋ฅผ ์“ฐ๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

 

- process.env๋Š” ์™ธ๋ถ€๊ฐ์ฒด๋กœ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ฐ์ฒด์ธ๋ฐ ์ด๊ฒƒ๋งˆ์ €๋„ nest๊ฐ€ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.

์ž์œ ์ž์žฌ๋กœ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Œ

 

์™ธ๋ถ€์—์„œ ์š”์ฒญ์„ ๊ฐ€์ ธ์™€ ๋‚ด config๋กœ ๋งŒ๋“œ๋Š” ๋น„๋™๊ธฐ ์ž‘์—… ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ?

-> load๋ผ๋Š” ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋จ!

 

const getEnv = async () => {
  const response = await axios.get('/๋น„๋ฐ€ํ‚ค์š”์ฒญ')
  //์™ธ๋ถ€ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋น„๋ฐ€ํ‚ค๋ฅผ ์š”์ฒญํ•ด์„œ 
  return response.data;
  //๊ทธ๊ฒƒ์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค
};

@Module({
  imports: [ConfigModule.forRoot({ isGlobal: true, load: [getEnv] })],
  controllers: [AppController],
  providers: [AppService, ConfigService],
})

 

์ด๋Ÿฐ ๋ฐฉ์‹์ด๋‹ค.