Skip to content

Commit 9ccd79e

Browse files
committed
refactor the code and sanitize the code by code seperation.
1 parent c149315 commit 9ccd79e

File tree

21 files changed

+579
-211
lines changed

21 files changed

+579
-211
lines changed

README.md

Lines changed: 306 additions & 38 deletions
Large diffs are not rendered by default.

libs/shared/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ export * from './interfaces';
66
export * from './secrets';
77
export * from './exception';
88
export * from './cqrs';
9+
export * from './utils';
10+
export * from './logger';
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Global, Module } from '@nestjs/common';
2+
import { LoggerModule as PinoLoggerModule } from 'nestjs-pino';
3+
import { configVariables } from '@shared';
4+
import type { IncomingMessage, ServerResponse } from 'http';
5+
6+
@Global()
7+
@Module({
8+
imports: [
9+
PinoLoggerModule.forRootAsync({
10+
useFactory: () => ({
11+
pinoHttp: {
12+
level: configVariables.logger.level,
13+
14+
transport:
15+
configVariables.nodeEnv !== 'production'
16+
? {
17+
target: 'pino-pretty',
18+
options: {
19+
colorize: true,
20+
translateTime: 'yyyy-mm-dd HH:MM:ss.l o',
21+
ignore: 'pid,hostname',
22+
},
23+
}
24+
: undefined,
25+
26+
genReqId: (req: IncomingMessage & { id?: string }) =>
27+
(req.headers['x-request-id'] as string) ?? Date.now().toString(),
28+
29+
serializers: {
30+
req(req: IncomingMessage & { id?: string }) {
31+
return {
32+
method: req.method,
33+
url: req.url,
34+
id: req.id,
35+
};
36+
},
37+
res(res: ServerResponse) {
38+
return {
39+
statusCode: res.statusCode,
40+
};
41+
},
42+
err(err: Error) {
43+
return {
44+
type: err.name,
45+
message: err.message,
46+
stack: err.stack,
47+
};
48+
},
49+
},
50+
51+
redact: {
52+
paths: [
53+
'req.headers.authorization',
54+
'req.body.password',
55+
'req.body.token',
56+
'*.password',
57+
'*.token',
58+
],
59+
censor: '**REDACTED**',
60+
},
61+
62+
autoLogging:
63+
configVariables.nodeEnv === 'development'
64+
? {
65+
ignore: (req: IncomingMessage) => req.url === '/health',
66+
}
67+
: false,
68+
},
69+
70+
forRoutes: [],
71+
}),
72+
}),
73+
],
74+
exports: [PinoLoggerModule],
75+
})
76+
export class LoggerModule {}
Lines changed: 21 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,38 @@
1-
import * as dotenv from 'dotenv';
2-
import { join } from 'path';
1+
import { getEnvVariable, loadEnvironment } from '@shared/utils';
32

4-
dotenv.config({ path: join(process.cwd(), 'src/environment/.env') });
5-
6-
if (process.env.NODE_ENV === 'production') {
7-
dotenv.config({
8-
path: join(process.cwd(), 'src/environment/.env.prod'),
9-
override: true,
10-
});
11-
}
12-
13-
function getEnvVariable(key: string): string {
14-
const value = process.env[key];
15-
if (!value) {
16-
throw new Error(`Environment variable ${key} is not defined`);
17-
}
18-
return value;
19-
}
20-
21-
const PORT = parseInt(getEnvVariable('PORT'), 10);
22-
const DB_NAME = getEnvVariable('DB_NAME');
23-
const DB_TYPE = getEnvVariable('DB_TYPE') as 'postgres' | 'mysql' | 'mongodb';
24-
const DB_HOST = getEnvVariable('DB_HOST');
25-
const DB_PORT = parseInt(getEnvVariable('DB_PORT'), 10);
26-
const DB_USERNAME = getEnvVariable('DB_USERNAME');
27-
const DB_PASSWORD = getEnvVariable('DB_PASSWORD');
28-
const SWAGGER_DOCS = getEnvVariable('SWAGGER_DOCS');
29-
const JWT_SECRET = getEnvVariable('JWT_SECRET');
30-
const NODE_ENV = getEnvVariable('NODE_ENV') as
31-
| 'development'
32-
| 'production'
33-
| 'test';
34-
const SESSION_SECRET = getEnvVariable('SESSION_SECRET');
35-
const API_VERSION = getEnvVariable('API_VERSION');
36-
const PUBLIC_KEY = getEnvVariable('PUBLIC_KEY');
37-
const LOG_LEVEL = getEnvVariable('LOG_LEVEL');
38-
const SENTRY_DSN = getEnvVariable('SENTRY_DSN');
3+
loadEnvironment();
394

405
export const configVariables = {
41-
port: PORT,
6+
port: Number(getEnvVariable('PORT')),
427
database: {
43-
name: DB_NAME,
44-
type: DB_TYPE,
45-
host: DB_HOST,
46-
port: DB_PORT,
47-
username: DB_USERNAME,
48-
password: DB_PASSWORD,
8+
name: getEnvVariable('DB_NAME'),
9+
type: getEnvVariable('DB_TYPE') as 'postgres',
10+
host: getEnvVariable('DB_HOST'),
11+
port: Number(getEnvVariable('DB_PORT')),
12+
username: getEnvVariable('DB_USERNAME'),
13+
password: getEnvVariable('DB_PASSWORD'),
4914
},
5015
swagger: {
51-
docs: SWAGGER_DOCS,
16+
url: getEnvVariable('SWAGGER_URL'),
17+
title: getEnvVariable('SWAGGER_TITLE'),
18+
description: getEnvVariable('SWAGGER_DESCRIPTION'),
19+
version: getEnvVariable('SWAGGER_VERSION'),
5220
},
5321
jwt: {
54-
secret: JWT_SECRET,
22+
secret: getEnvVariable('JWT_SECRET'),
5523
},
5624
session: {
57-
secret: SESSION_SECRET,
25+
secret: getEnvVariable('SESSION_SECRET'),
5826
},
5927
api: {
60-
version: API_VERSION,
28+
version: getEnvVariable('API_VERSION'),
6129
},
62-
nodeEnv: NODE_ENV,
63-
publicKey: PUBLIC_KEY,
30+
nodeEnv: getEnvVariable('NODE_ENV'),
31+
publicKey: getEnvVariable('PUBLIC_KEY'),
6432
sentry: {
65-
dsn: SENTRY_DSN,
33+
dsn: getEnvVariable('SENTRY_DSN', false),
6634
},
6735
logger: {
68-
level: LOG_LEVEL,
36+
level: getEnvVariable('LOG_LEVEL'),
6937
},
70-
} as const;
38+
};

libs/shared/src/shared.module.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { DynamicModule, Global, Module } from '@nestjs/common';
22
import { CqrsModule } from '@nestjs/cqrs';
33
import { JwtModule } from '@nestjs/jwt';
44
import { CqrsMediator } from './cqrs/cqrs.mediator';
5+
import { configVariables } from './secrets';
6+
import { LoggerModule } from 'nestjs-pino';
57
// Import other shared services, guards, helpers, interceptors as needed
68

79
@Global()
@@ -11,7 +13,14 @@ export class SharedBaseModule {
1113
return {
1214
module: SharedBaseModule,
1315
global: true,
14-
imports: [CqrsModule, JwtModule],
16+
imports: [
17+
CqrsModule,
18+
JwtModule.register({
19+
secret: configVariables.jwt.secret,
20+
signOptions: { expiresIn: '1d' },
21+
}),
22+
LoggerModule,
23+
],
1524
providers: [
1625
CqrsMediator,
1726
// add other shared providers here

libs/shared/src/utils/env.utils.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export function getEnvVariable(key: string, required = true): string {
2+
const value = process.env[key];
3+
4+
if (required && (!value || value.trim() === '')) {
5+
throw new Error(`Environment variable ${key} is not defined`);
6+
}
7+
8+
return value || '';
9+
}

libs/shared/src/utils/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './env.utils';
2+
export * from './load-env.utils';
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as dotenv from 'dotenv';
2+
import { join } from 'path';
3+
4+
export function loadEnvironment() {
5+
const basePath = join(process.cwd(), 'src/environment/.env');
6+
7+
dotenv.config({ path: basePath });
8+
9+
const envFileMap: Record<string, string> = {
10+
production: '.env.prod',
11+
development: '.env',
12+
test: '.env.test',
13+
docker: '.env.docker',
14+
};
15+
16+
const nodeEnv = process.env.NODE_ENV || 'development';
17+
const envFile = envFileMap[nodeEnv];
18+
19+
if (envFile && envFile !== '.env') {
20+
dotenv.config({
21+
path: join(process.cwd(), `src/environment/${envFile}`),
22+
override: true,
23+
});
24+
}
25+
}

src/app.module.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,10 @@ import { AppService } from './app.service';
77
import { DatabaseService } from '@config/database-connect.msg';
88
import { AppDataSource } from '@config/typeorm.config';
99
import { HealthModule } from '@modules/health/health.module';
10-
import { LoggerModule } from '@modules/logger';
1110
import { SharedBaseModule } from '@shared';
1211

1312
@Module({
1413
imports: [
15-
LoggerModule,
1614
HealthModule,
1715
TypeOrmModule.forRoot(AppDataSource.options),
1816
AutomapperModule.forRoot({

0 commit comments

Comments
 (0)