Skip to content

Commit b286009

Browse files
authored
Merge pull request #8 from gbgabiola/chore/configs
Enhance the codebase by adding config files
2 parents ec00874 + ac6d1e9 commit b286009

11 files changed

Lines changed: 165 additions & 23 deletions

.env.stage.dev

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
DB_HOST=localhost
2+
DB_PORT= 5432
3+
DB_USERNAME=postgres
4+
DB_PASSWORD=mypass
5+
DB_NAME=task-management
6+
JWT_SECRET=hKs2z!Zzm\[p'fbY.X?e'[<cSaXfu.5NxUu<WQHZ3Gm'&xHub)zZ@*x`k#;Z'z=9

.env.stage.prod

Whitespace-only changes.

package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,19 @@
1010
"build": "nest build",
1111
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
1212
"start": "nest start",
13-
"start:dev": "nest start --watch",
14-
"start:debug": "nest start --debug --watch",
15-
"start:prod": "node dist/main",
13+
"start:dev": "STAGE=dev nest start --watch",
14+
"start:debug": "STAGE=dev nest start --debug --watch",
15+
"start:prod": "STAGE=prod node dist/main",
1616
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
17-
"test": "jest",
17+
"test": "STAGE=dev jest",
1818
"test:watch": "jest --watch",
1919
"test:cov": "jest --coverage",
2020
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
2121
"test:e2e": "jest --config ./test/jest-e2e.json"
2222
},
2323
"dependencies": {
2424
"@nestjs/common": "^8.0.0",
25+
"@nestjs/config": "^1.0.3",
2526
"@nestjs/core": "^8.0.0",
2627
"@nestjs/jwt": "^8.0.0",
2728
"@nestjs/passport": "^8.0.1",
@@ -31,6 +32,7 @@
3132
"bcrypt": "^5.0.1",
3233
"class-transformer": "^0.4.0",
3334
"class-validator": "^0.13.1",
35+
"joi": "^17.4.2",
3436
"passport": "^0.5.0",
3537
"passport-jwt": "^4.0.0",
3638
"pg": "^8.7.1",

src/app.module.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,29 @@ import { Module } from '@nestjs/common';
22
import { TypeOrmModule } from '@nestjs/typeorm';
33
import { TasksModule } from './tasks/tasks.module';
44
import { AuthModule } from './auth/auth.module';
5+
import { ConfigModule, ConfigService } from '@nestjs/config';
6+
import { configValidationSchema } from './config.schema';
57

68
@Module({
79
imports: [
10+
ConfigModule.forRoot({
11+
envFilePath: [`.env.stage.${process.env.STAGE}`],
12+
validationSchema: configValidationSchema,
13+
}),
814
TasksModule,
9-
TypeOrmModule.forRoot({
10-
type: 'postgres',
11-
host: 'localhost',
12-
port: 5432,
13-
username: 'postgres',
14-
password: 'mypass',
15-
database: 'task-management',
16-
autoLoadEntities: true,
17-
synchronize: true,
15+
TypeOrmModule.forRootAsync({
16+
imports: [ConfigModule],
17+
inject: [ConfigService],
18+
useFactory: async (configService: ConfigService) => ({
19+
type: 'postgres',
20+
autoLoadEntities: true,
21+
synchronize: true,
22+
host: configService.get('DB_HOST'),
23+
port: configService.get('DB_PORT'),
24+
username: configService.get('DB_USERNAME'),
25+
password: configService.get('DB_PASSWORD'),
26+
database: configService.get('DB_NAME'),
27+
}),
1828
}),
1929
AuthModule,
2030
],

src/auth/auth.module.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,21 @@ import { UsersRepository } from './users.repository';
66
import { PassportModule } from '@nestjs/passport';
77
import { JwtModule } from '@nestjs/jwt';
88
import { JwtStrategy } from './jwt.strategy';
9+
import { ConfigModule, ConfigService } from '@nestjs/config';
910

1011
@Module({
1112
imports: [
13+
ConfigModule,
1214
PassportModule.register({ defaultStrategy: 'jwt' }),
13-
JwtModule.register({
14-
secret: 'superSecret1993',
15-
signOptions: {
16-
expiresIn: 3600,
17-
},
15+
JwtModule.registerAsync({
16+
imports: [ConfigModule],
17+
inject: [ConfigService],
18+
useFactory: async (configService: ConfigService) => ({
19+
secret: configService.get('JWT_SECRET'),
20+
signOptions: {
21+
expiresIn: 3600,
22+
},
23+
}),
1824
}),
1925
TypeOrmModule.forFeature([UsersRepository]),
2026
],

src/auth/jwt.strategy.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Injectable, UnauthorizedException } from '@nestjs/common';
2+
import { ConfigService } from '@nestjs/config';
23
import { PassportStrategy } from '@nestjs/passport';
34
import { InjectRepository } from '@nestjs/typeorm';
45
import { ExtractJwt, Strategy } from 'passport-jwt';
@@ -11,9 +12,10 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
1112
constructor(
1213
@InjectRepository(UsersRepository)
1314
private usersRepository: UsersRepository,
15+
private configService: ConfigService,
1416
) {
1517
super({
16-
secretOrKey: 'superSecret1993',
18+
secretOrKey: configService.get('JWT_SECRET'),
1719
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
1820
});
1921
}

src/config.schema.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as Joi from 'joi';
2+
3+
export const configValidationSchema = Joi.object({
4+
STAGE: Joi.string().required(),
5+
DB_HOST: Joi.string().required(),
6+
DB_PORT: Joi.number().default(5432).required(),
7+
DB_USERNAME: Joi.string().required(),
8+
DB_PASSWORD: Joi.string().required(),
9+
DB_NAME: Joi.string().required(),
10+
JWT_SECRET: Joi.string().required(),
11+
});

src/main.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import { ValidationPipe } from '@nestjs/common';
1+
import { Logger, ValidationPipe } from '@nestjs/common';
22
import { NestFactory } from '@nestjs/core';
33
import { AppModule } from './app.module';
44
import { TransformInterceptor } from './transform.interceptor';
55

66
async function bootstrap() {
7+
const logger = new Logger();
8+
const port = 3000;
79
const app = await NestFactory.create(AppModule);
810
app.useGlobalPipes(new ValidationPipe());
911
app.useGlobalInterceptors(new TransformInterceptor());
10-
await app.listen(3000);
12+
await app.listen(port);
13+
logger.log(`Application listening on port ${port}...`);
1114
}
1215
bootstrap();

src/tasks/tasks.controller.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
Controller,
44
Delete,
55
Get,
6+
Logger,
67
Param,
78
Patch,
89
Post,
@@ -21,13 +22,19 @@ import { TasksService } from './tasks.service';
2122
@Controller('tasks')
2223
@UseGuards(AuthGuard())
2324
export class TasksController {
25+
private logger = new Logger('TasksController');
2426
constructor(private tasksService: TasksService) {}
2527

2628
@Get()
2729
getTasks(
2830
@Query() filterDto: GetTasksFilterDto,
2931
@GetUser() user: User,
3032
): Promise<Task[]> {
33+
this.logger.verbose(
34+
`User "${
35+
user.username
36+
}" is retrieving all tasks. Filters: ${JSON.stringify(filterDto)}`,
37+
);
3138
return this.tasksService.getTasks(filterDto, user);
3239
}
3340

@@ -41,6 +48,11 @@ export class TasksController {
4148
@Body() createTaskDto: CreateTaskDto,
4249
@GetUser() user: User,
4350
): Promise<Task> {
51+
this.logger.verbose(
52+
`User "${user.username}" is creating a task. Data: ${JSON.stringify(
53+
createTaskDto,
54+
)}`,
55+
);
4456
return this.tasksService.createTask(createTaskDto, user);
4557
}
4658

src/tasks/tasks.repository.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { InternalServerErrorException, Logger } from '@nestjs/common';
12
import { User } from 'src/auth/user.entity';
23
import { EntityRepository, Repository } from 'typeorm';
34
import { CreateTaskDto } from './dto/create-task.dto';
@@ -7,6 +8,8 @@ import { Task } from './task.entity';
78

89
@EntityRepository(Task)
910
export class TasksRepository extends Repository<Task> {
11+
private logger = new Logger('TasksRepository', { timestamp: true });
12+
1013
async getTasks(filterDto: GetTasksFilterDto, user: User): Promise<Task[]> {
1114
const { status, search } = filterDto;
1215
const query = this.createQueryBuilder('task');
@@ -23,8 +26,18 @@ export class TasksRepository extends Repository<Task> {
2326
);
2427
}
2528

26-
const tasks = await query.getMany();
27-
return tasks;
29+
try {
30+
const tasks = await query.getMany();
31+
return tasks;
32+
} catch (error) {
33+
this.logger.error(
34+
`Failed to get tasks for user "${
35+
user.username
36+
}". Filters: ${JSON.stringify(filterDto)}`,
37+
error.stack,
38+
);
39+
throw new InternalServerErrorException();
40+
}
2841
}
2942

3043
async createTask(createTaskDto: CreateTaskDto, user: User): Promise<Task> {

0 commit comments

Comments
 (0)