Skip to content

Commit

Permalink
fix(): store validated and parsed env variables
Browse files Browse the repository at this point in the history
  • Loading branch information
kamilmysliwiec committed Feb 23, 2020
1 parent 57781bc commit f7c4da1
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 2 deletions.
3 changes: 3 additions & 0 deletions lib/config.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
export const CONFIGURATION_SERVICE_TOKEN = Symbol('CONFIG_SERVICE');
export const CONFIGURATION_TOKEN = 'CONFIGURATION_TOKEN';
export const CONFIGURATION_LOADER = 'CONFIGURATION_LOADER';
export const VALIDATED_ENV_LOADER = 'VALIDATED_ENV_LOADER';

export const PARTIAL_CONFIGURATION_KEY = 'PARTIAL_CONFIGURATION_KEY';
export const PARTIAL_CONFIGURATION_PROPNAME = 'KEY';
export const VALIDATED_ENV_PROPNAME = '_PROCESS_ENV_VALIDATED';
15 changes: 15 additions & 0 deletions lib/config.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
CONFIGURATION_LOADER,
CONFIGURATION_SERVICE_TOKEN,
CONFIGURATION_TOKEN,
VALIDATED_ENV_LOADER,
VALIDATED_ENV_PROPNAME,
} from './config.constants';
import { ConfigService } from './config.service';
import { ConfigFactory, ConfigModuleOptions } from './interfaces';
Expand All @@ -35,6 +37,7 @@ export class ConfigModule {
* @param options
*/
static forRoot(options: ConfigModuleOptions = {}): DynamicModule {
let validatedEnvConfig: Record<string, any> | undefined = undefined;
if (!options.ignoreEnvFile) {
if (options.validationSchema) {
let config = this.loadEnvFile(options);
Expand All @@ -53,6 +56,7 @@ export class ConfigModule {
if (error) {
throw new Error(`Config validation error: ${error.message}`);
}
validatedEnvConfig = validatedConfig;
this.assignVariablesToProcess(validatedConfig);
} else {
const config = this.loadEnvFile(options);
Expand All @@ -74,6 +78,17 @@ export class ConfigModule {
};
providers.push(configServiceProvider);

if (validatedEnvConfig) {
const validatedEnvConfigLoader = {
provide: VALIDATED_ENV_LOADER,
useFactory: (host: Record<string, any>) => {
host[VALIDATED_ENV_PROPNAME] = validatedEnvConfig;
},
inject: [CONFIGURATION_TOKEN],
};
providers.push(validatedEnvConfigLoader);
}

return {
module: ConfigModule,
global: options.isGlobal,
Expand Down
12 changes: 11 additions & 1 deletion lib/config.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Inject, Injectable, Optional } from '@nestjs/common';
import get from 'lodash.get';
import { isUndefined } from 'util';
import { CONFIGURATION_TOKEN } from './config.constants';
import {
CONFIGURATION_TOKEN,
VALIDATED_ENV_PROPNAME,
} from './config.constants';

@Injectable()
export class ConfigService {
Expand Down Expand Up @@ -35,6 +38,13 @@ export class ConfigService {
* @param defaultValue
*/
get<T = any>(propertyPath: string, defaultValue?: T): T | undefined {
const validatedEnvValue = get(
this.internalConfig[VALIDATED_ENV_PROPNAME],
propertyPath,
);
if (!isUndefined(validatedEnvValue)) {
return (validatedEnvValue as unknown) as T;
}
const processValue = get(process.env, propertyPath);
if (!isUndefined(processValue)) {
return (processValue as unknown) as T;
Expand Down
2 changes: 2 additions & 0 deletions tests/e2e/.env.valid
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
PORT=4000
DATABASE_NAME=test
14 changes: 14 additions & 0 deletions tests/e2e/validation-schema.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { join } from 'path';
import { ConfigService } from '../../lib';
import { AppModule } from '../src/app.module';

describe('Schema validation', () => {
Expand All @@ -19,4 +21,16 @@ describe('Schema validation', () => {
);
}
});

it(`should parse loaded env variables`, async () => {
const module = await Test.createTestingModule({
imports: [AppModule.withSchemaValidation(join(__dirname, '.env.valid'))],
}).compile();

app = module.createNestApplication();
await app.init();

const configService = app.get(ConfigService);
expect(typeof configService.get('PORT')).toEqual('number');
});
});
3 changes: 2 additions & 1 deletion tests/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,12 @@ export class AppModule {
};
}

static withSchemaValidation(): DynamicModule {
static withSchemaValidation(envFilePath?: string): DynamicModule {
return {
module: AppModule,
imports: [
ConfigModule.forRoot({
envFilePath,
validationSchema: Joi.object({
PORT: Joi.number().required(),
DATABASE_NAME: Joi.string().required(),
Expand Down

0 comments on commit f7c4da1

Please sign in to comment.