From af69127706c49cafeeab657c9714901fd70bdee3 Mon Sep 17 00:00:00 2001 From: aniebietafia Date: Sat, 31 Aug 2024 16:50:00 +0100 Subject: [PATCH 1/7] feat: config service to fetch environment variables --- .../src/config/config.service.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 brints-estate-api/src/config/config.service.ts diff --git a/brints-estate-api/src/config/config.service.ts b/brints-estate-api/src/config/config.service.ts new file mode 100644 index 0000000..18cdcf5 --- /dev/null +++ b/brints-estate-api/src/config/config.service.ts @@ -0,0 +1,22 @@ +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; + +@Injectable() +export class AppConfigService { + constructor(private readonly configService: ConfigService) {} + + getConfig() { + return { + database: { + dbHost: this.configService.get('DB_HOST') as string, + dbPort: this.configService.get('DB_PORT') as number, + dbUser: this.configService.get('DB_USER') as string, + dbPassword: this.configService.get('DB_PASSWORD') as string, + dbName: this.configService.get('DB_NAME') as string, + }, + app: { + port: this.configService.get('APP_PORT') as number, + }, + }; + } +} From ec92dd0dac1a9afa8aebd543647c7c7e69b7fac8 Mon Sep 17 00:00:00 2001 From: aniebietafia Date: Sat, 31 Aug 2024 16:50:32 +0100 Subject: [PATCH 2/7] feat: swagger documentation --- .../src/config/config.swagger.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 brints-estate-api/src/config/config.swagger.ts diff --git a/brints-estate-api/src/config/config.swagger.ts b/brints-estate-api/src/config/config.swagger.ts new file mode 100644 index 0000000..f021705 --- /dev/null +++ b/brints-estate-api/src/config/config.swagger.ts @@ -0,0 +1,21 @@ +import { INestApplication } from '@nestjs/common'; +import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; + +export function swaggerInitializer(app: INestApplication) { + const config = new DocumentBuilder() + .setTitle('Brints Estate API') + .setDescription( + 'The modern day Real Estate API simplifying the way we buy and sell properties', + ) + .addServer('http://localhost:3001', 'Development Server') + .addServer('https://brints-estate-api.herokuapp.com', 'Production Server') + .setTermsOfService('http://localhost:3001/terms') + .setLicense( + 'MIT', + 'https://github.com/Brints/nestjs-brints-group-estate/blob/main/LICENSE', + ) + .setVersion('1.0') + .build(); + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup('api-docs', app, document); +} From aa2690753d65d0b799d7ae1dbf8e5ad69c7c26e1 Mon Sep 17 00:00:00 2001 From: aniebietafia Date: Sat, 31 Aug 2024 16:51:08 +0100 Subject: [PATCH 3/7] feat: environment variables validations using joi --- .../src/config/environment.validation.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 brints-estate-api/src/config/environment.validation.ts diff --git a/brints-estate-api/src/config/environment.validation.ts b/brints-estate-api/src/config/environment.validation.ts new file mode 100644 index 0000000..65466d7 --- /dev/null +++ b/brints-estate-api/src/config/environment.validation.ts @@ -0,0 +1,28 @@ +// import Joi from '@hapi/joi'; +import * as Joi from 'joi'; + +// export const environmentValidationSchema = Joi.object({ +// APP_PORT: Joi.number().default(8000), +// DB_HOST: Joi.string().required(), +// DB_PORT: Joi.number().default(5432), +// DB_USER: Joi.string().required(), +// DB_PASSWORD: Joi.string().required(), +// DB_NAME: Joi.string().required(), +// NODE_ENV: Joi.string() +// .required() +// .valid('development', 'production', 'test') +// .default('development'), +// }); + +export const environmentValidationSchema = Joi.object({ + APP_PORT: Joi.number().port().default(8000), + DB_HOST: Joi.string().required(), + DB_PORT: Joi.number().port().default(5432), + DB_USER: Joi.string().required(), + DB_PASSWORD: Joi.string().required(), + DB_NAME: Joi.string().required(), + NODE_ENV: Joi.string() + .required() + .valid('development', 'production', 'test', 'staging') + .default('development'), +}); From 07518c80b282a6ca4dfa56bee9109572687d489c Mon Sep 17 00:00:00 2001 From: aniebietafia Date: Sat, 31 Aug 2024 16:52:03 +0100 Subject: [PATCH 4/7] updating scripts to load the proper environment --- brints-estate-api/package.json | 18 ++++--- brints-estate-api/yarn.lock | 98 ++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 6 deletions(-) diff --git a/brints-estate-api/package.json b/brints-estate-api/package.json index 36ad414..686ff59 100644 --- a/brints-estate-api/package.json +++ b/brints-estate-api/package.json @@ -1,7 +1,7 @@ { "name": "brints-estate-api", "version": "0.0.1", - "description": "", + "description": "A Real Estate API", "author": "", "private": true, "license": "UNLICENSED", @@ -9,17 +9,18 @@ "build": "nest build", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "start": "nest start", - "start:dev": "nest start --watch", - "start:debug": "nest start --debug --watch", - "start:prod": "node dist/main", + "start:dev": "NODE_ENV=development nest start --watch", + "start:debug": "NODE_ENV=development nest start --debug --watch", + "start:prod": "NODE_ENV=production node dist/main", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", - "test": "jest", + "test": "NODE_ENV=development jest", "test:watch": "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" }, "dependencies": { + "@hapi/joi": "^17.1.1", "@nestjs/common": "^10.4.1", "@nestjs/config": "^3.2.3", "@nestjs/core": "^10.4.1", @@ -29,6 +30,7 @@ "@nestjs/typeorm": "^10.0.2", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", + "joi": "^17.13.3", "pg": "^8.12.0", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", @@ -41,6 +43,7 @@ "@nestjs/schematics": "^10.1.4", "@nestjs/testing": "^10.4.1", "@types/express": "^4.17.21", + "@types/hapi__joi": "^17.1.14", "@types/jest": "^29.5.12", "@types/node": "^22.5.0", "@types/pg": "^8", @@ -67,7 +70,10 @@ "json", "ts" ], - "rootDir": "src", + "rootDir": "./", + "modulePaths": [ + "" + ], "testRegex": ".*\\.spec\\.ts$", "transform": { "^.+\\.(t|j)s$": "ts-jest" diff --git a/brints-estate-api/yarn.lock b/brints-estate-api/yarn.lock index 781188c..87570f4 100644 --- a/brints-estate-api/yarn.lock +++ b/brints-estate-api/yarn.lock @@ -530,6 +530,58 @@ __metadata: languageName: node linkType: hard +"@hapi/address@npm:^4.0.1": + version: 4.1.0 + resolution: "@hapi/address@npm:4.1.0" + dependencies: + "@hapi/hoek": "npm:^9.0.0" + checksum: 10c0/6f111f57d9ff72bab8f0a356cdc95f3a5561a347fedc5c2d398906a3754273db4f83e6f92f5d20759c95077f52d01837175a9128b705aef98101f2d34cabe3ac + languageName: node + linkType: hard + +"@hapi/formula@npm:^2.0.0": + version: 2.0.0 + resolution: "@hapi/formula@npm:2.0.0" + checksum: 10c0/93fd1768da51043e49e008a1556c68e9bbf19f6be4823a7c04ed982afaea8f7079f1d4a5452620fe6124976ea0867a6f42e69579fc74f9b9f3dac6bdcc1fc969 + languageName: node + linkType: hard + +"@hapi/hoek@npm:^9.0.0, @hapi/hoek@npm:^9.3.0": + version: 9.3.0 + resolution: "@hapi/hoek@npm:9.3.0" + checksum: 10c0/a096063805051fb8bba4c947e293c664b05a32b47e13bc654c0dd43813a1cec993bdd8f29ceb838020299e1d0f89f68dc0d62a603c13c9cc8541963f0beca055 + languageName: node + linkType: hard + +"@hapi/joi@npm:^17.1.1": + version: 17.1.1 + resolution: "@hapi/joi@npm:17.1.1" + dependencies: + "@hapi/address": "npm:^4.0.1" + "@hapi/formula": "npm:^2.0.0" + "@hapi/hoek": "npm:^9.0.0" + "@hapi/pinpoint": "npm:^2.0.0" + "@hapi/topo": "npm:^5.0.0" + checksum: 10c0/0c9fc1e8d26909b0bd1458728d10071170c5112980d455b865fca17964f65befe8b4c30a3d362d423ec60be77afd2d811d2e40a028d3b099adaba80b960db297 + languageName: node + linkType: hard + +"@hapi/pinpoint@npm:^2.0.0": + version: 2.0.1 + resolution: "@hapi/pinpoint@npm:2.0.1" + checksum: 10c0/b3072f2c57c9fa2e44d85168e253e331324158509e1c45dae2676f31555326410345fd2422f890c41201e2783c5e9bb8c7b0bdcf6abe01079742a943b0c300b9 + languageName: node + linkType: hard + +"@hapi/topo@npm:^5.0.0, @hapi/topo@npm:^5.1.0": + version: 5.1.0 + resolution: "@hapi/topo@npm:5.1.0" + dependencies: + "@hapi/hoek": "npm:^9.0.0" + checksum: 10c0/b16b06d9357947149e032bdf10151eb71aea8057c79c4046bf32393cb89d0d0f7ca501c40c0f7534a5ceca078de0700d2257ac855c15e59fe4e00bba2f25c86f + languageName: node + linkType: hard + "@humanwhocodes/module-importer@npm:^1.0.1": version: 1.0.1 resolution: "@humanwhocodes/module-importer@npm:1.0.1" @@ -1179,6 +1231,29 @@ __metadata: languageName: node linkType: hard +"@sideway/address@npm:^4.1.5": + version: 4.1.5 + resolution: "@sideway/address@npm:4.1.5" + dependencies: + "@hapi/hoek": "npm:^9.0.0" + checksum: 10c0/638eb6f7e7dba209053dd6c8da74d7cc995e2b791b97644d0303a7dd3119263bcb7225a4f6804d4db2bc4f96e5a9d262975a014f58eae4d1753c27cbc96ef959 + languageName: node + linkType: hard + +"@sideway/formula@npm:^3.0.1": + version: 3.0.1 + resolution: "@sideway/formula@npm:3.0.1" + checksum: 10c0/3fe81fa9662efc076bf41612b060eb9b02e846ea4bea5bd114f1662b7f1541e9dedcf98aff0d24400bcb92f113964a50e0290b86e284edbdf6346fa9b7e2bf2c + languageName: node + linkType: hard + +"@sideway/pinpoint@npm:^2.0.0": + version: 2.0.0 + resolution: "@sideway/pinpoint@npm:2.0.0" + checksum: 10c0/d2ca75dacaf69b8fc0bb8916a204e01def3105ee44d8be16c355e5f58189eb94039e15ce831f3d544f229889ccfa35562a0ce2516179f3a7ee1bbe0b71e55b36 + languageName: node + linkType: hard + "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" @@ -1366,6 +1441,13 @@ __metadata: languageName: node linkType: hard +"@types/hapi__joi@npm:^17.1.14": + version: 17.1.14 + resolution: "@types/hapi__joi@npm:17.1.14" + checksum: 10c0/f9324de0c9ac37097b5bddc997402e299b7a9ab098a27c22f808d363c8218f94180023117b0b99fe187bffa1f6e473744b7417054a3737b3360035c20274d792 + languageName: node + linkType: hard + "@types/http-errors@npm:*": version: 2.0.4 resolution: "@types/http-errors@npm:2.0.4" @@ -2271,6 +2353,7 @@ __metadata: dependencies: "@eslint/eslintrc": "npm:^3.1.0" "@eslint/js": "npm:^9.9.1" + "@hapi/joi": "npm:^17.1.1" "@nestjs/cli": "npm:^10.4.4" "@nestjs/common": "npm:^10.4.1" "@nestjs/config": "npm:^3.2.3" @@ -2282,6 +2365,7 @@ __metadata: "@nestjs/testing": "npm:^10.4.1" "@nestjs/typeorm": "npm:^10.0.2" "@types/express": "npm:^4.17.21" + "@types/hapi__joi": "npm:^17.1.14" "@types/jest": "npm:^29.5.12" "@types/node": "npm:^22.5.0" "@types/pg": "npm:^8" @@ -2295,6 +2379,7 @@ __metadata: eslint-plugin-prettier: "npm:^5.2.1" globals: "npm:^15.9.0" jest: "npm:^29.7.0" + joi: "npm:^17.13.3" pg: "npm:^8.12.0" prettier: "npm:^3.3.3" reflect-metadata: "npm:^0.2.2" @@ -4872,6 +4957,19 @@ __metadata: languageName: node linkType: hard +"joi@npm:^17.13.3": + version: 17.13.3 + resolution: "joi@npm:17.13.3" + dependencies: + "@hapi/hoek": "npm:^9.3.0" + "@hapi/topo": "npm:^5.1.0" + "@sideway/address": "npm:^4.1.5" + "@sideway/formula": "npm:^3.0.1" + "@sideway/pinpoint": "npm:^2.0.0" + checksum: 10c0/9262aef1da3f1bec5b03caf50c46368899fe03b8ff26cbe3d53af4584dd1049079fc97230bbf1500b6149db7cc765b9ee45f0deb24bb6fc3fa06229d7148c17f + languageName: node + linkType: hard + "js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" From 54fd71149094b3de549dbde2546d307db0e9a468 Mon Sep 17 00:00:00 2001 From: aniebietafia Date: Sat, 31 Aug 2024 16:53:00 +0100 Subject: [PATCH 5/7] refactor: removed datasource initialization --- brints-estate-api/src/main.ts | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/brints-estate-api/src/main.ts b/brints-estate-api/src/main.ts index b864c05..426a309 100644 --- a/brints-estate-api/src/main.ts +++ b/brints-estate-api/src/main.ts @@ -1,37 +1,20 @@ import { NestFactory } from '@nestjs/core'; +import { ConfigService } from '@nestjs/config'; import { Logger } from '@nestjs/common'; -import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { AppModule } from './app.module'; -import { initializeDataSource } from './database/data-source'; +import { swaggerInitializer } from './config/config.swagger'; async function bootstrap() { - await initializeDataSource(); + const app = await NestFactory.create(AppModule); + const configService = new ConfigService(); + const port = configService.get('APP_PORT'); const logger = new Logger(); - const app = await NestFactory.create(AppModule); - /** - * Swagger configuration - */ - const config = new DocumentBuilder() - .setTitle('Brints Estate API') - .setDescription( - 'The modern day Real Estate API simplifying the way we buy and sell properties', - ) - .addServer('http://localhost:3001', 'Development Server') - .addServer('https://brints-estate-api.herokuapp.com', 'Production Server') - .setTermsOfService('http://localhost:3001/terms') - .setLicense( - 'MIT', - 'https://github.com/Brints/nestjs-brints-group-estate/blob/main/LICENSE', - ) - .setVersion('1.0') - .build(); - const document = SwaggerModule.createDocument(app, config); - SwaggerModule.setup('api-docs', app, document); + swaggerInitializer(app); - await app.listen(3001); - logger.log('Application started on http://localhost:3001'); + await app.listen(port); + logger.log(`Application is running on ${await app.getUrl()}`); } bootstrap(); From c769eb4089a9437254a157ffe3cf919afb9e86d1 Mon Sep 17 00:00:00 2001 From: aniebietafia Date: Sat, 31 Aug 2024 16:54:23 +0100 Subject: [PATCH 6/7] refactor: function to create data source --- brints-estate-api/src/database/data-source.ts | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/brints-estate-api/src/database/data-source.ts b/brints-estate-api/src/database/data-source.ts index b2536ce..59ba0c1 100644 --- a/brints-estate-api/src/database/data-source.ts +++ b/brints-estate-api/src/database/data-source.ts @@ -1,20 +1,32 @@ +import { DataSource } from 'typeorm'; + import { User } from 'src/users/entities/user.entity'; import { UserAuth } from 'src/users/entities/userAuth.entity'; -import { DataSource } from 'typeorm'; -const AppDataSource = new DataSource({ - type: 'postgres', - host: 'localhost', - port: 5432, - username: 'postgres', - password: 'postgres', - database: 'brints-estate-backend', - synchronize: true, - entities: [User, UserAuth], - // entities: [__dirname + '/**/*.entity{.ts,.js}'], -}); +const isDevelopment = process.env.NODE_ENV === 'development'; + +interface DataSourceConfig { + dbHost: string; + dbPort: number; + dbUser: string; + dbPassword: string; + dbName: string; +} + +export function createDataSource(config: DataSourceConfig) { + return new DataSource({ + type: 'postgres', + host: config.dbHost, + port: config.dbPort, + username: config.dbUser, + password: config.dbPassword, + database: config.dbName, + synchronize: isDevelopment, + entities: [User, UserAuth], + }); +} -export async function initializeDataSource() { +export async function initializeDataSource(AppDataSource: DataSource) { try { if (!AppDataSource.isInitialized) { await AppDataSource.initialize(); @@ -25,5 +37,3 @@ export async function initializeDataSource() { throw error; } } - -export default AppDataSource; From f4cd2ef13e32cd31a7bf155e9e71905e1681ae0d Mon Sep 17 00:00:00 2001 From: aniebietafia Date: Sat, 31 Aug 2024 16:56:43 +0100 Subject: [PATCH 7/7] refactor: used config service to connect to database --- brints-estate-api/src/app.module.ts | 38 +++++++++++++++++------------ 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/brints-estate-api/src/app.module.ts b/brints-estate-api/src/app.module.ts index 648fc8d..d3fb3c9 100644 --- a/brints-estate-api/src/app.module.ts +++ b/brints-estate-api/src/app.module.ts @@ -1,29 +1,37 @@ import { Module } from '@nestjs/common'; -import { ConfigModule } from '@nestjs/config'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; -import { AuthModule } from './auth/auth.module'; import { UsersModule } from './users/users.module'; -// import { TypeOrmModule } from '@nestjs/typeorm'; +import { AuthModule } from './auth/auth.module'; +import { environmentValidationSchema } from './config/environment.validation'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, + envFilePath: !process.env.NODE_ENV + ? '.env' + : `.env.${process.env.NODE_ENV}`, + validationSchema: environmentValidationSchema, + }), + TypeOrmModule.forRootAsync({ + inject: [ConfigService], + useFactory: (configService: ConfigService) => ({ + type: 'postgres', + host: configService.get('DB_HOST'), + port: configService.get('DB_PORT'), + username: configService.get('DB_USER'), + password: configService.get('DB_PASSWORD'), + database: configService.get('DB_NAME'), + autoLoadEntities: process.env.NODE_ENV === 'development', + synchronize: process.env.NODE_ENV === 'development', + entities: [__dirname + '/**/*.entity{.ts,.js}'], + // entities: [User, UserAuth], + }), }), AuthModule, UsersModule, - // TypeOrmModule.forRootAsync({ - // useFactory: () => ({ - // type: 'postgres', - // host: 'localhost', - // port: 5432, - // username: 'postgres', - // password: 'postgres', - // database: 'brints-estate-backend', - // synchronize: true, - // autoLoadEntities: true, - // }) - // }) ], }) export class AppModule {}