- Can be used without DI - just instantiate
- You get types - no explicit type imports etc
- You can define computed fields etc
- You can refactor ENV names without affecting the service fields :)
- You can structure and nest the fileds however you want
- Super simple to reason about & maintain - no need to rely on magic
Last active
January 22, 2023 19:12
-
-
Save emildimitrov/27bb02266f166944ced64d0524a3d4bb to your computer and use it in GitHub Desktop.
Best nestjs config approach
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Global, Module } from '@nestjs/common'; | |
import { ConfigService } from './config.service'; | |
@Global() | |
@Module({ | |
providers: [ConfigService], | |
exports: [ConfigService], | |
}) | |
export class ConfigModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
IsBoolean, | |
IsEnum, | |
IsNotEmpty, | |
IsNumber, | |
IsOptional, | |
} from 'class-validator'; | |
export class ConfigOptions { | |
//mind boolean casting with class-transformer - use decorator @ToBoolean | |
@IsBoolean() | |
@IsOptional() | |
DEBUG?: boolean = false; | |
@IsNotEmpty() | |
POSTGRES_HOST: string; | |
@IsNotEmpty() | |
POSTGRES_USERNAME: string; | |
@IsNotEmpty() | |
POSTGRES_PASSWORD: string; | |
@IsNotEmpty() | |
REDIS_HOST: string; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable } from '@nestjs/common'; | |
import { plainToClass } from 'class-transformer'; | |
import { validateSync } from 'class-validator'; | |
import * as dotenv from 'dotenv'; | |
import { ConfigOptions } from './config.options'; | |
//sets to process.env what we have in .env | |
dotenv.config(); | |
/** | |
* @description | |
* - Can be used without DI - just instantiate | |
* - You get types - no explicit type imports etc | |
* - You should expose getter for each field you want | |
* - You can define computed fields etc, but everything | |
* - You can refactor ENV names without affecting the service fields :) | |
* which this service exposes should be read only | |
* - prefer grouping fields with same prefix - makes things more readable | |
* @export | |
* @class ConfigService | |
*/ | |
@Injectable() | |
export class ConfigService { | |
private readonly env: ConfigOptions; | |
constructor() { | |
const transformed = plainToClass(ConfigOptions, process.env); | |
const errors = validateSync(transformed, { | |
/** | |
* Will strip not declared with decorator in options fields | |
*/ | |
whitelist: true, | |
}); | |
if (errors.length > 0) { | |
errors.forEach((e) => { | |
console.error(e.toString()); | |
}); | |
process.exit(1); | |
} | |
this.env = transformed; | |
} | |
get debug() { | |
return this.env.DEBUG; | |
} | |
get postgres() { | |
return { | |
host: this.env.POSTGRES_HOST, | |
username: this.env.POSTGRES_USERNAME, | |
password: this.env.POSTGRES_PASSWORD, | |
}; | |
} | |
get redis() { | |
return { | |
host: this.env.REDIS_HOST, | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment