diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e69de29 diff --git a/docker-compose.yml b/docker-compose.yml index a6997b2..4609c45 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,9 +7,9 @@ services: env_file: - .env environment: - - POSTGRES_DB=${POSTGRES_DB} - - POSTGRES_USER=${POSTGRES_USER} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - POSTGRES_DB=${DATABASE_NAME} + - POSTGRES_USER=${DATABASE_USER} + - POSTGRES_PASSWORD=${DATABASE_PASSWORD} volumes: - db-data:/var/lib/postgresql/data networks: diff --git a/package.json b/package.json index c3ef73e..5b4936f 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "test:e2e": "jest --config ./test/jest-e2e.json" }, "dependencies": { - "@aws-amplify/backend": "^0.5.5", + "@aws-amplify/backend": "^1.2.2", "@aws-amplify/cli": "^12.8.2", "@babel/core": "^7.23.5", "@babel/preset-env": "^7.23.5", @@ -69,7 +69,7 @@ "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "babel-cli": "^6.26.0", - "dotenv": "^16.3.1", + "dotenv": "^16.4.5", "eslint": "^8.42.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", diff --git a/src/clients/assessments/assessments.client.ts b/src/clients/assessments/assessments.client.ts index a449f85..1cac271 100644 --- a/src/clients/assessments/assessments.client.ts +++ b/src/clients/assessments/assessments.client.ts @@ -1,13 +1,12 @@ import { HttpService } from '@nestjs/axios'; import { Injectable } from '@nestjs/common'; import { AssessmentEntity } from 'src/models/assessment/assessment.entity'; -import { EnvironmentConfigService } from 'src/services/environment-config/environment-config.service'; +import { envs } from 'src/types/environment-config'; @Injectable() export class AssessmentsClient { constructor( private readonly httpService: HttpService, - private readonly environmentConfigService: EnvironmentConfigService, ) {} async getAssessmentByBootcampId( @@ -16,7 +15,7 @@ export class AssessmentsClient { try { const response = await this.httpService .get( - `${this.environmentConfigService.ASSESSEMENT_SERVICE_URL}/bootcamp/${bootcampId}`, + `${envs.ASSESSMENT_SERVICE_URL}/bootcamp/${bootcampId}`, ) .toPromise(); return response.data; diff --git a/src/clients/bottcamps/bootcamps.client.ts b/src/clients/bottcamps/bootcamps.client.ts index 3cb0da9..ad98d84 100644 --- a/src/clients/bottcamps/bootcamps.client.ts +++ b/src/clients/bottcamps/bootcamps.client.ts @@ -1,20 +1,19 @@ import { HttpService } from '@nestjs/axios'; import { Injectable } from '@nestjs/common'; import { BootcampEntity } from 'src/models/bootcamp/bootcamp.entity'; -import { EnvironmentConfigService } from 'src/services/environment-config/environment-config.service'; +import { envs } from 'src/types/environment-config'; @Injectable() export class BootcampsClient { constructor( private readonly httpService: HttpService, - private readonly environmentConfigService: EnvironmentConfigService, ) {} async getScoreAverage(bootcampId: string): Promise { try { const response = await this.httpService .get( - `${this.environmentConfigService.BOOTCAMP_SERVICE_URL}/score/${bootcampId}`, + `${envs.BOOTCAMP_SERVICE_URL}/score/${bootcampId}`, ) .toPromise(); return response.data.score; @@ -29,12 +28,9 @@ export class BootcampsClient { ): Promise { try { const updateScoreResponse = await this.httpService - .post( - `${this.environmentConfigService.BOOTCAMP_SERVICE_URL}/score/${bootcampId}`, - { - score, - }, - ) + .post(`${envs.BOOTCAMP_SERVICE_URL}/score/${bootcampId}`, { + score, + }) .toPromise(); return updateScoreResponse.data; } catch (error) { @@ -46,7 +42,7 @@ export class BootcampsClient { try { const response = await this.httpService .post( - `${this.environmentConfigService.BOOTCAMP_SERVICE_URL}/score/recalculate/${bootcampId}`, + `${envs.BOOTCAMP_SERVICE_URL}/score/recalculate/${bootcampId}`, ) .toPromise(); return response.data; diff --git a/src/clients/files/files.client.ts b/src/clients/files/files.client.ts index 6fb8cbb..46071b0 100644 --- a/src/clients/files/files.client.ts +++ b/src/clients/files/files.client.ts @@ -2,13 +2,12 @@ import { HttpService } from '@nestjs/axios'; import { Injectable } from '@nestjs/common'; import axios from 'axios'; import * as FormData from 'form-data'; -import { EnvironmentConfigService } from 'src/services/environment-config/environment-config.service'; +import { envs } from 'src/types/environment-config'; @Injectable() export class FilesClient { constructor( private readonly httpService: HttpService, - private readonly environmentConfigService: EnvironmentConfigService, ) {} async uploadOne(file: Express.Multer.File | any) { @@ -22,7 +21,7 @@ export class FilesClient { const options = { method: 'POST', - url: `${this.environmentConfigService.FILE_SERVICE_URL}/upload`, + url: `${envs.FILE_SERVICE_URL}/upload`, headers: formData.getHeaders(), data: formData, } as const; @@ -37,7 +36,7 @@ export class FilesClient { async findOne(id: string) { try { return this.httpService.get( - `${this.environmentConfigService.FILE_SERVICE_URL}/${id}`, + `${envs.FILE_SERVICE_URL}/${id}`, { responseType: 'arraybuffer' }, ); } catch (err) { diff --git a/src/clients/reviews/reviews.client.ts b/src/clients/reviews/reviews.client.ts index 8694e93..5f4da94 100644 --- a/src/clients/reviews/reviews.client.ts +++ b/src/clients/reviews/reviews.client.ts @@ -1,19 +1,18 @@ import { HttpService } from '@nestjs/axios'; import { Injectable } from '@nestjs/common'; -import { EnvironmentConfigService } from 'src/services/environment-config/environment-config.service'; +import { envs } from 'src/types/environment-config'; @Injectable() export class ReviewsClient { constructor( private readonly httpService: HttpService, - private readonly environmentConfigService: EnvironmentConfigService, ) {} async getScoreAverage(bootcampId: string): Promise { try { const response = await this.httpService .get( - `${this.environmentConfigService.REVIEW_SERVICE_URL}/bootcamp/${bootcampId}/average`, + `${envs.REVIEW_SERVICE_URL}/bootcamp/${bootcampId}/average`, ) .toPromise(); return response.data; diff --git a/src/config/database/type-orm-config.ts b/src/config/database/type-orm-config.ts new file mode 100644 index 0000000..0e181f6 --- /dev/null +++ b/src/config/database/type-orm-config.ts @@ -0,0 +1,17 @@ +import { envs } from 'src/types/environment-config'; +import { DataSourceOptions } from 'typeorm'; + +const config: DataSourceOptions = { + type: 'postgres', + host: envs.DATABASE_HOST, + port: envs.DATABASE_PORT, + username: envs.DATABASE_USER, + password: envs.DATABASE_PASSWORD, + database: envs.DATABASE_NAME, + // Only include necessary properties + entities: ['dist/**/*.entity{.ts,.js}'], + migrations: ['dist/migrations/*{.ts,.js}'], // Array of strings for migration file paths + synchronize: envs.NODE_ENV === 'dev', +}; + +export default config; diff --git a/src/modules/app.module.ts b/src/modules/app.module.ts index 5db34a5..43c20c7 100644 --- a/src/modules/app.module.ts +++ b/src/modules/app.module.ts @@ -5,7 +5,6 @@ import { RouterModule } from '@nestjs/core'; import { PassportModule } from '@nestjs/passport'; import { AppController } from '../controllers/app.controller'; import { AppService } from '../services/app.service'; -import { environmentConfigSchema } from '../types/environment-config'; import { AssessmentsModule } from './assessments/assessments.module'; import { BootcampsModule } from './bootcamps/bootcamps.module'; import { FilesModule } from './files/files.module'; @@ -28,10 +27,6 @@ import { UsersModule } from './users/users.module'; ConfigModule.forRoot({ envFilePath: ['.env.develop', '.env'], isGlobal: true, - validationSchema: environmentConfigSchema, - validationOptions: { - allowUnknown: true, - }, }), RouterModule.register([ { diff --git a/src/modules/assessments/assessments.module.ts b/src/modules/assessments/assessments.module.ts index 4b70731..6ad201e 100644 --- a/src/modules/assessments/assessments.module.ts +++ b/src/modules/assessments/assessments.module.ts @@ -7,7 +7,6 @@ import { BootcampsClient } from 'src/clients/bottcamps/bootcamps.client'; import { AssessmentsController } from 'src/controllers/assessments/assessments.controller'; import { AssessmentEntity } from 'src/models/assessment/assessment.entity'; import { AssessmentsService } from 'src/services/assessments/assessments.service'; -import { EnvironmentConfigService } from 'src/services/environment-config/environment-config.service'; import { jwtConstants } from 'src/utils/jwt/constants.jwt'; @Module({ @@ -22,6 +21,6 @@ import { jwtConstants } from 'src/utils/jwt/constants.jwt'; TypeOrmModule.forFeature([AssessmentEntity]), ], controllers: [AssessmentsController], - providers: [AssessmentsService, BootcampsClient, EnvironmentConfigService], + providers: [AssessmentsService, BootcampsClient], }) export class AssessmentsModule {} diff --git a/src/modules/bootcamps/bootcamps.module.ts b/src/modules/bootcamps/bootcamps.module.ts index aee10c6..0799005 100644 --- a/src/modules/bootcamps/bootcamps.module.ts +++ b/src/modules/bootcamps/bootcamps.module.ts @@ -19,7 +19,6 @@ import { ReviewEntity } from 'src/models/review/review.entity'; import { TestimonialEntity } from 'src/models/testimonial/testimonial.entity'; import { UserEntity } from 'src/models/user/user.entity'; import { BootcampsService } from 'src/services/bootcamps/bootcamps.service'; -import { EnvironmentConfigService } from 'src/services/environment-config/environment-config.service'; import { jwtConstants } from 'src/utils/jwt/constants.jwt'; @Module({ @@ -52,7 +51,6 @@ import { jwtConstants } from 'src/utils/jwt/constants.jwt'; FilesClient, ReviewsClient, AssessmentsClient, - EnvironmentConfigService, ], exports: [TypeOrmModule], }) diff --git a/src/modules/environment-config/environment-config.module.ts b/src/modules/environment-config/environment-config.module.ts deleted file mode 100644 index a81bbe4..0000000 --- a/src/modules/environment-config/environment-config.module.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Module } from '@nestjs/common'; -import { ConfigModule } from '@nestjs/config'; -import { EnvironmentConfigService } from 'src/services/environment-config/environment-config.service'; - -@Module({ - imports: [ConfigModule], - controllers: [], - providers: [EnvironmentConfigService], - exports: [EnvironmentConfigService], -}) -export class EnvironmentConfigModule {} diff --git a/src/modules/programs/programs.module.ts b/src/modules/programs/programs.module.ts index 580b19a..47d3b17 100644 --- a/src/modules/programs/programs.module.ts +++ b/src/modules/programs/programs.module.ts @@ -6,7 +6,6 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { FilesClient } from 'src/clients/files/files.client'; import { ProgramsController } from 'src/controllers/programs/programs.controller'; import { ProgramEntity } from 'src/models/program/program.entity'; -import { EnvironmentConfigService } from 'src/services/environment-config/environment-config.service'; import { ProgramsService } from 'src/services/programs/programs.service'; import { jwtConstants } from 'src/utils/jwt/constants.jwt'; @@ -22,7 +21,7 @@ import { jwtConstants } from 'src/utils/jwt/constants.jwt'; TypeOrmModule.forFeature([ProgramEntity]), ], controllers: [ProgramsController], - providers: [ProgramsService, FilesClient, EnvironmentConfigService], + providers: [ProgramsService, FilesClient], exports: [TypeOrmModule], }) export class ProgramsModule {} diff --git a/src/modules/typeorm/db.module.ts b/src/modules/typeorm/db.module.ts index 15ffdd3..4ec4cc8 100644 --- a/src/modules/typeorm/db.module.ts +++ b/src/modules/typeorm/db.module.ts @@ -1,37 +1,10 @@ import { Module } from '@nestjs/common'; -import { ConfigModule, ConfigService } from '@nestjs/config'; -import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'; -import { EnvironmentConfigService } from 'src/services/environment-config/environment-config.service'; +import { TypeOrmModule, } from '@nestjs/typeorm'; import { DataSource } from 'typeorm'; -import type { EnvironmentConfig } from '../../types/environment-config'; -import { EnvironmentConfigModule } from '../environment-config/environment-config.module'; +import config from 'src/config/database/type-orm-config'; @Module({ - imports: [ - TypeOrmModule.forRootAsync({ - imports: [ConfigModule, EnvironmentConfigModule], - inject: [ConfigService, EnvironmentConfigService], - useFactory: ( - config: ConfigService, - environmentConfigService: EnvironmentConfigService, - ) => { - return { - type: 'postgres', - host: environmentConfigService.DATABASE_HOST, - port: environmentConfigService.DATABASE_PORT, - username: environmentConfigService.DATABASE_USER, - password: environmentConfigService.DATABASE_PASSWORD, - database: environmentConfigService.DATABASE_NAME, - autoLoadEntities: true, - synchronize: - environmentConfigService.NODE_ENV === - ('dev' satisfies EnvironmentConfig['NODE_ENV']), - } as TypeOrmModuleOptions; - }, - }), - ], - providers: [ConfigModule, DbModule], - exports: [], + imports: [TypeOrmModule.forRoot(config)], }) export class DbModule { constructor(private dataSource: DataSource) {} diff --git a/src/services/environment-config/environment-config.service.ts b/src/services/environment-config/environment-config.service.ts deleted file mode 100644 index 1d2f252..0000000 --- a/src/services/environment-config/environment-config.service.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import type { EnvironmentConfig } from '../../types/environment-config'; - -@Injectable() -export class EnvironmentConfigService implements EnvironmentConfig { - FILE_SERVICE_URL: string; - DATABASE_HOST: string; - DATABASE_PORT: number; - DATABASE_USER: string; - DATABASE_PASSWORD: string; - DATABASE_NAME: string; - REVIEW_SERVICE_URL: string; - BOOTCAMP_SERVICE_URL: string; - ASSESSEMENT_SERVICE_URL: string; - NODE_ENV: EnvironmentConfig['NODE_ENV']; - - constructor(private config: ConfigService) { - this.FILE_SERVICE_URL = config.get('FILE_SERVICE_URL'); - this.DATABASE_HOST = config.get('DATABASE_HOST'); - this.DATABASE_PORT = config.get('DATABASE_PORT'); - this.DATABASE_USER = config.get('DATABASE_USER'); - this.DATABASE_PASSWORD = config.get('DATABASE_PASSWORD'); - this.DATABASE_NAME = config.get('DATABASE_NAME'); - this.REVIEW_SERVICE_URL = config.get('REVIEW_SERVICE_URL'); - this.BOOTCAMP_SERVICE_URL = config.get('BOOTCAMP_SERVICE_URL'); - this.ASSESSEMENT_SERVICE_URL = config.get('ASSESSEMENT_SERVICE_URL'); - this.NODE_ENV = config.get('NODE_ENV'); - } -} diff --git a/src/types/environment-config.ts b/src/types/environment-config.ts index d8e7b84..108fc90 100644 --- a/src/types/environment-config.ts +++ b/src/types/environment-config.ts @@ -1,4 +1,18 @@ +import 'dotenv/config' import * as Joi from 'joi'; +interface EnvironmentConfig { + DATABASE_HOST: string; + DATABASE_PORT: number; + DATABASE_USER: string; + DATABASE_PASSWORD: string; + DATABASE_NAME: string; + NODE_ENV: 'dev' | 'production'; + PORT: number; + FILE_SERVICE_URL: string; + REVIEW_SERVICE_URL: string; + BOOTCAMP_SERVICE_URL: string; + ASSESSMENT_SERVICE_URL: string; +} const environmentConfigSchema = Joi.object({ DATABASE_HOST: Joi.string().required(), @@ -7,24 +21,34 @@ const environmentConfigSchema = Joi.object({ DATABASE_PASSWORD: Joi.string().required(), DATABASE_NAME: Joi.string().required(), NODE_ENV: Joi.string().valid('dev', 'production').required(), + PORT: Joi.number().required(), FILE_SERVICE_URL: Joi.string().uri().required(), REVIEW_SERVICE_URL: Joi.string().uri().required(), BOOTCAMP_SERVICE_URL: Joi.string().uri().required(), - ASSESSEMENT_SERVICE_URL: Joi.string().uri().required(), -}); + ASSESSMENT_SERVICE_URL: Joi.string().uri().required(), +}).unknown() -interface EnvironmentConfig { - DATABASE_HOST: string; - DATABASE_PORT: number; - DATABASE_USER: string; - DATABASE_PASSWORD: string; - DATABASE_NAME: string; - NODE_ENV: 'dev' | 'production'; - FILE_SERVICE_URL: string; - REVIEW_SERVICE_URL: string; - BOOTCAMP_SERVICE_URL: string; - ASSESSEMENT_SERVICE_URL: string; + +const { error, value } = environmentConfigSchema.validate(process.env); + +if (error) { + throw new Error(`Config Validation ${error.message}`); } -export { environmentConfigSchema }; -export type { EnvironmentConfig }; +const envVars: EnvironmentConfig = value; + +export const envs = { + PORTS: envVars.PORT, + DATABASE_HOST: envVars.DATABASE_HOST, + DATABASE_PORT: envVars.DATABASE_PORT, + DATABASE_USER: envVars.DATABASE_USER, + DATABASE_PASSWORD: envVars.DATABASE_PASSWORD, + DATABASE_NAME: envVars.DATABASE_NAME, + NODE_ENV: envVars.NODE_ENV, + PORT: envVars.PORT, + FILE_SERVICE_URL: envVars.FILE_SERVICE_URL, + REVIEW_SERVICE_URL: envVars.REVIEW_SERVICE_URL, + BOOTCAMP_SERVICE_URL: envVars.BOOTCAMP_SERVICE_URL, + ASSESSMENT_SERVICE_URL: envVars.ASSESSMENT_SERVICE_URL, +}; +