Skip to content

Commit

Permalink
config files
Browse files Browse the repository at this point in the history
  • Loading branch information
mrkeksz committed Oct 19, 2023
1 parent 5065a8a commit 54323fc
Show file tree
Hide file tree
Showing 20 changed files with 280 additions and 24 deletions.
18 changes: 18 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Default environment variables for all environments.
# ".env.local" and ".env.test.local" files has higher priority than ".env" and ".env.test" files.

# Application supports variables in environment variables.
# Example:
# APP_URL=mywebsite.com
# SUPPORT_EMAIL=support@${APP_URL}

# Description: Node environment
# Type: string
# Options: production, development, test
# Default: production
NODE_ENV=production

# Description: Port to run the server on
# Type: number
# Default: 3000
PORT=3000
1 change: 1 addition & 0 deletions .env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NODE_ENV=test
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# compiled output
# Compiled output
/dist
/node_modules
error-graph.json
Expand Down Expand Up @@ -34,3 +34,7 @@ lerna-debug.log*
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

# Local settings
.env.local
.env.test.local
90 changes: 88 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,25 @@
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"lint:check": "eslint \"{src,apps,libs,test}/**/*.ts\"",
"test": "jest",
"test:watch": "jest --watch",
"test": "NODE_ENV=test jest",
"test:watch": "NODE_ENV=test jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
"test:debug": "NODE_ENV=test node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "NODE_ENV=test jest --config ./test/jest-e2e.json"
},
"engines": {
"node": ">=18.18.0"
},
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.0.0",
"@nestjs/devtools-integration": "^0.1.5",
"@nestjs/mapped-types": "*",
"@nestjs/platform-express": "^10.0.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"joi": "^17.11.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.1"
},
Expand Down
17 changes: 14 additions & 3 deletions src/app.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
import {Test, TestingModule} from '@nestjs/testing'
import {AppController} from './app.controller'
import {AppService} from './app.service'
import {configModule, configProviders} from './config'
import {ServerConfigService} from './config/server/server.config.service'
import {EnvironmentConfigService} from './config/environment/environment.config.service'

describe('AppController', () => {
let appController: AppController
let serverConfigService: ServerConfigService
let environmentConfigService: EnvironmentConfigService

beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({
imports: [configModule],
controllers: [AppController],
providers: [AppService],
providers: [AppService, ...configProviders],
}).compile()

appController = app.get<AppController>(AppController)
appController = app.get(AppController)
serverConfigService = app.get(ServerConfigService)
environmentConfigService = app.get(EnvironmentConfigService)
})

describe('root', () => {
it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!')
expect(appController.getHello()).toBe(`Hello World!
Port: ${serverConfigService.port}
Is development: ${environmentConfigService.isDevelopment}
Test: ${environmentConfigService.test}`)
})
})
})
10 changes: 5 additions & 5 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ import {APP_FILTER, APP_INTERCEPTOR, APP_PIPE} from '@nestjs/core'
import {HttpExceptionFilter} from './filters/http-exception.filter'
import {LoggingInterceptor} from './interceptors/logging.interceptor'
import {TimeoutInterceptor} from './interceptors/timeout.interceptor'

const isDev = process.env['NODE_ENV'] !== 'production'
import {NODE_ENV} from './config/environment/environment.config.constants'
import {configModule, configProviders} from './config'

@Module({
imports: [
DevtoolsModule.register({
http: isDev,
}),
configModule,
DevtoolsModule.register({http: process.env[NODE_ENV.name] === NODE_ENV.options.DEVELOPMENT}),
UsersModule,
],
controllers: [AppController],
Expand All @@ -39,6 +38,7 @@ const isDev = process.env['NODE_ENV'] !== 'production'
provide: APP_INTERCEPTOR,
useClass: TimeoutInterceptor,
},
...configProviders,
],
})
export class AppModule implements NestModule {
Expand Down
12 changes: 11 additions & 1 deletion src/app.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import {Injectable} from '@nestjs/common'
import {ServerConfigService} from './config/server/server.config.service'
import {EnvironmentConfigService} from './config/environment/environment.config.service'

@Injectable()
export class AppService {
constructor(
private readonly serverConfigService: ServerConfigService,
private readonly environmentConfigService: EnvironmentConfigService,
) {}

getHello(): string {
return 'Hello World!'
return `Hello World!
Port: ${this.serverConfigService.port}
Is development: ${this.environmentConfigService.isDevelopment}
Test: ${this.environmentConfigService.test}`
}
}
16 changes: 16 additions & 0 deletions src/config/environment/environment.config.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export type NodeEnvType = 'development' | 'production' | 'test'
export const NODE_ENV = {
name: 'NODE_ENV',
options: {
DEVELOPMENT: 'development',
PRODUCTION: 'production',
TEST: 'test',
},
defaultValue: 'production',
}

export type TestType = 1
export const TEST = {
name: 'TEST',
defaultValue: 1,
}
8 changes: 8 additions & 0 deletions src/config/environment/environment.config.env-validation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as Joi from 'joi'
import {NODE_ENV} from './environment.config.constants'

export default {
[NODE_ENV.name]: Joi.string()
.valid(...Object.values(NODE_ENV.options))
.default(NODE_ENV.defaultValue),
}
24 changes: 24 additions & 0 deletions src/config/environment/environment.config.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {Injectable} from '@nestjs/common'
import {ConfigService} from '@nestjs/config'
import {NODE_ENV, TEST, TestType} from './environment.config.constants'

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

get isDevelopment(): boolean {
return this.configService.get(NODE_ENV.name) === NODE_ENV.options.DEVELOPMENT
}

get isProduction(): boolean {
return this.configService.get(NODE_ENV.name) === NODE_ENV.options.PRODUCTION
}

get isTest(): boolean {
return this.configService.get(NODE_ENV.name) === NODE_ENV.options.TEST
}

get test(): number {
return this.configService.get(TEST.name) as TestType
}
}
5 changes: 5 additions & 0 deletions src/config/environment/environment.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {TEST} from './environment.config.constants'

export default () => ({
[TEST.name]: TEST.defaultValue,
})
38 changes: 38 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {ServerConfigService} from './server/server.config.service'
import {EnvironmentConfigService} from './environment/environment.config.service'
import environmentConfig from './environment/environment.config'
import * as Joi from 'joi'
import {ConfigModule} from '@nestjs/config/dist/config.module'
import serverConfigEnvValidation from './server/server.config.env-validation'
import environmentConfigEnvValidation from './environment/environment.config.env-validation'
import * as process from 'process'
import {NODE_ENV} from './environment/environment.config.constants'

// Add all config services here
export const configProviders = [EnvironmentConfigService, ServerConfigService]

// Add all custom config here
const configsForLoad = [environmentConfig]

// Add all config validation here
const validationSchema = Joi.object({
...serverConfigEnvValidation,
...environmentConfigEnvValidation,
})

export const configModule = ConfigModule.forRoot({
envFilePath:
process.env[NODE_ENV.name] === NODE_ENV.options.TEST
? ['.env.test.local', '.env.test', '.env']
: ['.env.local', '.env'],
cache: true,
validationOptions: {
allowUnknown: true,
abortEarly: true,
convert: true,
dateFormat: 'iso',
},
expandVariables: true,
load: configsForLoad,
validationSchema,
})
Loading

0 comments on commit 54323fc

Please sign in to comment.