From 82d2bea6927b9d5d85e1219c1f5299cd95dec1d5 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 13 Nov 2024 13:43:34 +0900 Subject: [PATCH 1/8] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20use=20nest?= =?UTF-8?q?js/config=20in=20config=20lib?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.sample | 11 ++- libs/application-config/project.json | 9 --- libs/application-config/src/index.ts | 2 - .../src/lib/applications-config.spec.ts | 73 ------------------- .../src/lib/applications-config.ts | 33 --------- .../src/lib/subgraphs-config.spec.ts | 12 --- .../src/lib/subgraphs-config.ts | 10 --- libs/{application-config => config}/README.md | 0 .../eslint.config.js | 0 .../jest.config.ts | 4 +- libs/config/project.json | 9 +++ libs/config/src/index.ts | 4 + libs/config/src/lib/applications.config.ts | 20 +++++ libs/config/src/lib/database.config.ts | 6 ++ libs/config/src/lib/subgraphs.config.ts | 10 +++ .../tsconfig.json | 0 .../tsconfig.lib.json | 0 .../tsconfig.spec.json | 0 package.json | 1 + pnpm-lock.yaml | 23 ++++++ tsconfig.base.json | 4 +- 21 files changed, 84 insertions(+), 147 deletions(-) delete mode 100644 libs/application-config/project.json delete mode 100644 libs/application-config/src/index.ts delete mode 100644 libs/application-config/src/lib/applications-config.spec.ts delete mode 100644 libs/application-config/src/lib/applications-config.ts delete mode 100644 libs/application-config/src/lib/subgraphs-config.spec.ts delete mode 100644 libs/application-config/src/lib/subgraphs-config.ts rename libs/{application-config => config}/README.md (100%) rename libs/{application-config => config}/eslint.config.js (100%) rename libs/{application-config => config}/jest.config.ts (69%) create mode 100644 libs/config/project.json create mode 100644 libs/config/src/index.ts create mode 100644 libs/config/src/lib/applications.config.ts create mode 100644 libs/config/src/lib/database.config.ts create mode 100644 libs/config/src/lib/subgraphs.config.ts rename libs/{application-config => config}/tsconfig.json (100%) rename libs/{application-config => config}/tsconfig.lib.json (100%) rename libs/{application-config => config}/tsconfig.spec.json (100%) diff --git a/.env.sample b/.env.sample index 8ac643e..215f993 100644 --- a/.env.sample +++ b/.env.sample @@ -1,8 +1,11 @@ -GATEWAY_HOST=localhost +GATEWAY_HOST=http://localhost GATEWAY_PORT=3333 -USER_HOST=localhost +USER_HOST=http://localhost USER_PORT=15001 -TASK_HOST=localhost -TASK_PORT=15002 \ No newline at end of file +TASK_HOST=http://localhost +TASK_PORT=15002 + +DATABASE_USER=test +DATABASE_PASSWORD=test diff --git a/libs/application-config/project.json b/libs/application-config/project.json deleted file mode 100644 index 54220f1..0000000 --- a/libs/application-config/project.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "applications-config", - "$schema": "../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "libs/application-config/src", - "projectType": "library", - "tags": [], - "// targets": "to see all targets run: nx show project applications-config --web", - "targets": {} -} diff --git a/libs/application-config/src/index.ts b/libs/application-config/src/index.ts deleted file mode 100644 index 1721aef..0000000 --- a/libs/application-config/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './lib/applications-config'; -export * from './lib/subgraphs-config'; diff --git a/libs/application-config/src/lib/applications-config.spec.ts b/libs/application-config/src/lib/applications-config.spec.ts deleted file mode 100644 index 6e7389b..0000000 --- a/libs/application-config/src/lib/applications-config.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -describe('Service Configurations', () => { - const originalEnv = process.env; - - beforeEach(() => { - jest.resetModules(); - process.env = { ...originalEnv }; - }); - - afterEach(() => { - process.env = originalEnv; - }); - - it('should use default values when environment variables are not set', () => { - const { - gatewayConfig, - userSubGraph, - taskSubGraph, - } = require('./applications-config'); - - expect(gatewayConfig).toEqual({ - host: 'http://localhost', - name: 'gateway', - port: '3333', - }); - - expect(userSubGraph).toEqual({ - host: 'http://localhost', - name: 'user', - port: '15001', - }); - - expect(taskSubGraph).toEqual({ - host: 'http://localhost', - name: 'task', - port: '15002', - }); - }); - - it('should use environment variables when they are set', () => { - process.env['GATEWAY_HOST'] = 'gateway.example.com'; - process.env['GATEWAY_PORT'] = '4000'; - process.env['USER_HOST'] = 'user.example.com'; - process.env['USER_PORT'] = '5000'; - process.env['TASK_HOST'] = 'task.example.com'; - process.env['TASK_PORT'] = '6000'; - - jest.resetModules(); - - const { - gatewayConfig, - userSubGraph, - taskSubGraph, - } = require('./applications-config'); - - expect(gatewayConfig).toEqual({ - host: 'gateway.example.com', - name: 'gateway', - port: '4000', - }); - - expect(userSubGraph).toEqual({ - host: 'user.example.com', - name: 'user', - port: '5000', - }); - - expect(taskSubGraph).toEqual({ - host: 'task.example.com', - name: 'task', - port: '6000', - }); - }); -}); diff --git a/libs/application-config/src/lib/applications-config.ts b/libs/application-config/src/lib/applications-config.ts deleted file mode 100644 index 63f4909..0000000 --- a/libs/application-config/src/lib/applications-config.ts +++ /dev/null @@ -1,33 +0,0 @@ -interface ApplicationConfig { - host: string; - port: string; - name: string; -} - -const DEFAULT_HOST = 'http://localhost'; - -const DEFAULT_PORT = { - user: '15001', - task: '15002', - gateway: '3333', -}; - -// Gateway -export const gatewayConfig: ApplicationConfig = { - host: process.env['GATEWAY_HOST'] ?? DEFAULT_HOST, - port: process.env['GATEWAY_PORT'] ?? DEFAULT_PORT.gateway, - name: 'gateway', -}; - -// Graphql -export const userSubGraph: ApplicationConfig = { - host: process.env['USER_HOST'] ?? DEFAULT_HOST, - port: process.env['USER_PORT'] ?? DEFAULT_PORT.user, - name: 'user', -}; - -export const taskSubGraph: ApplicationConfig = { - host: process.env['TASK_HOST'] ?? DEFAULT_HOST, - port: process.env['TASK_PORT'] ?? DEFAULT_PORT.task, - name: 'task', -}; diff --git a/libs/application-config/src/lib/subgraphs-config.spec.ts b/libs/application-config/src/lib/subgraphs-config.spec.ts deleted file mode 100644 index 4782a64..0000000 --- a/libs/application-config/src/lib/subgraphs-config.spec.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { subgraphsConfig } from './subgraphs-config'; -import { userSubGraph } from './applications-config'; - -describe('subgraphsConfig', () => { - it('should have the correct configuration for the user subgraph', () => { - expect(subgraphsConfig).toHaveLength(1); - expect(subgraphsConfig[0]).toEqual({ - name: userSubGraph.name, - url: `${userSubGraph.host}:${userSubGraph.port}/graphql`, - }); - }); -}); diff --git a/libs/application-config/src/lib/subgraphs-config.ts b/libs/application-config/src/lib/subgraphs-config.ts deleted file mode 100644 index 4c59dd4..0000000 --- a/libs/application-config/src/lib/subgraphs-config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ServiceEndpointDefinition } from '@apollo/gateway'; - -import { userSubGraph } from './applications-config'; - -export const subgraphsConfig: ServiceEndpointDefinition[] = [ - { - name: userSubGraph.name, - url: `${userSubGraph.host}:${userSubGraph.port}/graphql`, - }, -]; diff --git a/libs/application-config/README.md b/libs/config/README.md similarity index 100% rename from libs/application-config/README.md rename to libs/config/README.md diff --git a/libs/application-config/eslint.config.js b/libs/config/eslint.config.js similarity index 100% rename from libs/application-config/eslint.config.js rename to libs/config/eslint.config.js diff --git a/libs/application-config/jest.config.ts b/libs/config/jest.config.ts similarity index 69% rename from libs/application-config/jest.config.ts rename to libs/config/jest.config.ts index a7ffe20..bb3bf75 100644 --- a/libs/application-config/jest.config.ts +++ b/libs/config/jest.config.ts @@ -1,10 +1,10 @@ export default { - displayName: 'applications-config', + displayName: 'config', preset: '../../jest.preset.js', testEnvironment: 'node', transform: { '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], }, moduleFileExtensions: ['ts', 'js', 'html'], - coverageDirectory: '../../coverage/libs/application-config', + coverageDirectory: '../../coverage/libs/config', }; diff --git a/libs/config/project.json b/libs/config/project.json new file mode 100644 index 0000000..281a94f --- /dev/null +++ b/libs/config/project.json @@ -0,0 +1,9 @@ +{ + "name": "config", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/config/src", + "projectType": "library", + "tags": [], + "// targets": "to see all targets run: nx show project config --web", + "targets": {} +} diff --git a/libs/config/src/index.ts b/libs/config/src/index.ts new file mode 100644 index 0000000..b9aab1e --- /dev/null +++ b/libs/config/src/index.ts @@ -0,0 +1,4 @@ +export * from './lib/applications.config'; +export * from './lib/database.config'; + +export * from './lib/subgraphs.config'; diff --git a/libs/config/src/lib/applications.config.ts b/libs/config/src/lib/applications.config.ts new file mode 100644 index 0000000..d8655dd --- /dev/null +++ b/libs/config/src/lib/applications.config.ts @@ -0,0 +1,20 @@ +import { registerAs } from '@nestjs/config'; + +const DEFAULT_HOST = 'http://localhost'; + +const DEFAULT_PORT = { + user: '15001', + task: '15002', + gateway: '3333', +}; + +export const gatewayConfig = registerAs('gateway', () => ({ + host: process.env['GATEWAY_HOST'] ?? DEFAULT_HOST, + port: process.env['GATEWAY_PORT'] ?? DEFAULT_PORT.gateway, +})); + +export const userAppConfig = registerAs('userApp', () => ({ + host: process.env['USER_HOST'] ?? DEFAULT_HOST, + port: process.env['USER_PORT'] ?? DEFAULT_PORT.user, + name: 'user', +})); diff --git a/libs/config/src/lib/database.config.ts b/libs/config/src/lib/database.config.ts new file mode 100644 index 0000000..f3be4ac --- /dev/null +++ b/libs/config/src/lib/database.config.ts @@ -0,0 +1,6 @@ +import { registerAs } from '@nestjs/config'; + +export const databaseConfig = registerAs('database', () => ({ + host: process.env['DATABASE_HOST'], + port: process.env['DATABASE_PORT'] || 5432, +})); diff --git a/libs/config/src/lib/subgraphs.config.ts b/libs/config/src/lib/subgraphs.config.ts new file mode 100644 index 0000000..cfd8c66 --- /dev/null +++ b/libs/config/src/lib/subgraphs.config.ts @@ -0,0 +1,10 @@ +import { ServiceEndpointDefinition } from '@apollo/gateway'; + +import { userAppConfig } from './applications.config'; + +export const subgraphsConfig: ServiceEndpointDefinition[] = [ + { + name: userAppConfig.name, + url: `${userAppConfig['host'] || ''}:${userAppConfig['port']}/graphql`, + }, +]; diff --git a/libs/application-config/tsconfig.json b/libs/config/tsconfig.json similarity index 100% rename from libs/application-config/tsconfig.json rename to libs/config/tsconfig.json diff --git a/libs/application-config/tsconfig.lib.json b/libs/config/tsconfig.lib.json similarity index 100% rename from libs/application-config/tsconfig.lib.json rename to libs/config/tsconfig.lib.json diff --git a/libs/application-config/tsconfig.spec.json b/libs/config/tsconfig.spec.json similarity index 100% rename from libs/application-config/tsconfig.spec.json rename to libs/config/tsconfig.spec.json diff --git a/package.json b/package.json index 59c504b..7d43631 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@apollo/subgraph": "^2.5.5", "@nestjs/apollo": "^12.2.1", "@nestjs/common": "^10.4.7", + "@nestjs/config": "^3.3.0", "@nestjs/core": "^10.4.7", "@nestjs/graphql": "^12.2.1", "@nestjs/platform-express": "^10.4.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eeee887..0ef137c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: '@nestjs/common': specifier: ^10.4.7 version: 10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/config': + specifier: ^3.3.0 + version: 3.3.0(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(rxjs@7.8.1) '@nestjs/core': specifier: ^10.4.7 version: 10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.7)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -1279,6 +1282,12 @@ packages: class-validator: optional: true + '@nestjs/config@3.3.0': + resolution: {integrity: sha512-pdGTp8m9d0ZCrjTpjkUbZx6gyf2IKf+7zlkrPNMsJzYZ4bFRRTpXrnj+556/5uiI6AfL5mMrJc2u7dB6bvM+VA==} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + rxjs: ^7.1.0 + '@nestjs/core@10.4.7': resolution: {integrity: sha512-AIpQzW/vGGqSLkKvll1R7uaSNv99AxZI2EFyVJPNGDgFsfXaohfV1Ukl6f+s75Km+6Fj/7aNl80EqzNWQCS8Ig==} peerDependencies: @@ -2892,6 +2901,10 @@ packages: domutils@3.1.0: resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + dotenv-expand@10.0.0: + resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} + engines: {node: '>=12'} + dotenv-expand@11.0.6: resolution: {integrity: sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==} engines: {node: '>=12'} @@ -7459,6 +7472,14 @@ snapshots: tslib: 2.7.0 uid: 2.0.2 + '@nestjs/config@3.3.0(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(rxjs@7.8.1)': + dependencies: + '@nestjs/common': 10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1) + dotenv: 16.4.5 + dotenv-expand: 10.0.0 + lodash: 4.17.21 + rxjs: 7.8.1 + '@nestjs/core@10.4.7(@nestjs/common@10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.7)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1)': dependencies: '@nestjs/common': 10.4.7(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -9439,6 +9460,8 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 + dotenv-expand@10.0.0: {} + dotenv-expand@11.0.6: dependencies: dotenv: 16.4.5 diff --git a/tsconfig.base.json b/tsconfig.base.json index db56ae1..91bb2ed 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -15,8 +15,8 @@ "skipDefaultLibCheck": true, "baseUrl": ".", "paths": { - "@graphql-federation-workspace/applications-config": [ - "libs/application-config/src/index.ts" + "@libs/config": [ + "libs/config/src/index.ts" ], "@prompt/user-prompt-log-entity": [ "libs/prompt/domain/user-prompt-log-entity/src/index.ts" From 338f26b58255847b19c7ead07f9b755f93cf2c37 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 13 Nov 2024 13:56:51 +0900 Subject: [PATCH 2/8] =?UTF-8?q?test:=20=F0=9F=A7=AA=20add=20test=20cases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/config/src/index.ts | 1 - .../src/lib/applications.config.spec.ts | 41 +++++++++++++++++++ libs/config/src/lib/database.config.spec.ts | 32 +++++++++++++++ libs/config/src/lib/subgraphs.config.ts | 10 ----- 4 files changed, 73 insertions(+), 11 deletions(-) create mode 100644 libs/config/src/lib/applications.config.spec.ts create mode 100644 libs/config/src/lib/database.config.spec.ts delete mode 100644 libs/config/src/lib/subgraphs.config.ts diff --git a/libs/config/src/index.ts b/libs/config/src/index.ts index b9aab1e..7e0686c 100644 --- a/libs/config/src/index.ts +++ b/libs/config/src/index.ts @@ -1,4 +1,3 @@ export * from './lib/applications.config'; export * from './lib/database.config'; -export * from './lib/subgraphs.config'; diff --git a/libs/config/src/lib/applications.config.spec.ts b/libs/config/src/lib/applications.config.spec.ts new file mode 100644 index 0000000..b35fc0d --- /dev/null +++ b/libs/config/src/lib/applications.config.spec.ts @@ -0,0 +1,41 @@ +import { gatewayConfig, userAppConfig } from './applications.config'; + +describe('Config Tests', () => { + describe('gatewayConfig', () => { + it('should return default values when environment variables are not set', () => { + const config = gatewayConfig(); + expect(config.host).toBe('http://localhost'); + expect(config.port).toBe('3333'); + }); + + it('should return environment values when environment variables are set', () => { + process.env['GATEWAY_HOST'] = 'http://gateway-host'; + process.env['GATEWAY_PORT'] = '4000'; + const config = gatewayConfig(); + expect(config.host).toBe('http://gateway-host'); + expect(config.port).toBe('4000'); + delete process.env['GATEWAY_HOST']; + delete process.env['GATEWAY_PORT']; + }); + }); + + describe('userAppConfig', () => { + it('should return default values when environment variables are not set', () => { + const config = userAppConfig(); + expect(config.host).toBe('http://localhost'); + expect(config.port).toBe('15001'); + expect(config.name).toBe('user'); + }); + + it('should return environment values when environment variables are set', () => { + process.env['USER_HOST'] = 'http://user-host'; + process.env['USER_PORT'] = '5000'; + const config = userAppConfig(); + expect(config.host).toBe('http://user-host'); + expect(config.port).toBe('5000'); + expect(config.name).toBe('user'); + delete process.env['USER_HOST']; + delete process.env['USER_PORT']; + }); + }); +}); \ No newline at end of file diff --git a/libs/config/src/lib/database.config.spec.ts b/libs/config/src/lib/database.config.spec.ts new file mode 100644 index 0000000..28b87f6 --- /dev/null +++ b/libs/config/src/lib/database.config.spec.ts @@ -0,0 +1,32 @@ +import { databaseConfig } from './database.config'; + +describe('databaseConfig', () => { + const OLD_ENV = process.env; + + beforeEach(() => { + jest.resetModules(); // Clears the cache + process.env = { ...OLD_ENV }; // Make a copy of the old environment + }); + + afterAll(() => { + process.env = OLD_ENV; // Restore old environment + }); + + it('should return the correct database host and port from environment variables', () => { + process.env['DATABASE_HOST'] = 'localhost'; + process.env['DATABASE_PORT'] = '3306'; + + const config = databaseConfig(); + expect(config.host).toBe('localhost'); + expect(config.port).toBe('3306'); + }); + + it('should return the default port if DATABASE_PORT is not set', () => { + process.env['DATABASE_HOST'] = 'localhost'; + delete process.env['DATABASE_PORT']; + + const config = databaseConfig(); + expect(config.host).toBe('localhost'); + expect(config.port).toBe(5432); + }); +}); \ No newline at end of file diff --git a/libs/config/src/lib/subgraphs.config.ts b/libs/config/src/lib/subgraphs.config.ts deleted file mode 100644 index cfd8c66..0000000 --- a/libs/config/src/lib/subgraphs.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ServiceEndpointDefinition } from '@apollo/gateway'; - -import { userAppConfig } from './applications.config'; - -export const subgraphsConfig: ServiceEndpointDefinition[] = [ - { - name: userAppConfig.name, - url: `${userAppConfig['host'] || ''}:${userAppConfig['port']}/graphql`, - }, -]; From 9bcbec81e7e1a78b273962ac970fbc516a9e4abb Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 13 Nov 2024 13:57:32 +0900 Subject: [PATCH 3/8] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20ConfigModu?= =?UTF-8?q?le.forRoot=20in=20AppModule?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/gateway/src/app/app.module.ts | 30 ++++++++++++++++---- apps/gateway/src/main.ts | 10 +++++-- apps/users-application/src/app/app.module.ts | 10 ++++++- apps/users-application/src/main.ts | 10 +++++-- libs/config/src/index.ts | 1 - 5 files changed, 47 insertions(+), 14 deletions(-) diff --git a/apps/gateway/src/app/app.module.ts b/apps/gateway/src/app/app.module.ts index 72200ac..1e0e9c7 100644 --- a/apps/gateway/src/app/app.module.ts +++ b/apps/gateway/src/app/app.module.ts @@ -1,20 +1,38 @@ import { IntrospectAndCompose } from '@apollo/gateway'; +import { gatewayConfig, userAppConfig } from '@libs/config'; import { ApolloGatewayDriver, ApolloGatewayDriverConfig } from '@nestjs/apollo'; import { Module } from '@nestjs/common'; +import { ConfigModule, ConfigService } from '@nestjs/config'; import { GraphQLModule } from '@nestjs/graphql'; -import { subgraphsConfig } from '@graphql-federation-workspace/applications-config'; import { AppController } from './app.controller'; import { AppService } from './app.service'; @Module({ imports: [ - GraphQLModule.forRoot({ + ConfigModule.forRoot({ + isGlobal: true, + load: [gatewayConfig, userAppConfig], + }), + GraphQLModule.forRootAsync({ + imports: [ConfigModule], + inject: [ConfigService], driver: ApolloGatewayDriver, - gateway: { - supergraphSdl: new IntrospectAndCompose({ - subgraphs: subgraphsConfig, - }), + useFactory: (configService: ConfigService) => { + const userAppConfig = configService.get('userApp'); + return { + driver: ApolloGatewayDriver, + gateway: { + supergraphSdl: new IntrospectAndCompose({ + subgraphs: [ + { + name: userAppConfig.name, + url: `${userAppConfig.host}:${userAppConfig.port}/graphql`, + }, + ], + }), + }, + }; }, }), ], diff --git a/apps/gateway/src/main.ts b/apps/gateway/src/main.ts index 271affc..10666c2 100644 --- a/apps/gateway/src/main.ts +++ b/apps/gateway/src/main.ts @@ -4,17 +4,21 @@ */ import { Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; import { NestFactory } from '@nestjs/core'; -import { gatewayConfig } from '@graphql-federation-workspace/applications-config'; import { AppModule } from './app/app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); - const port = gatewayConfig.port; + + const configService = app.get(ConfigService); + const config = configService.get('gateway'); + const host = config.host; + const port = config.port; await app.listen(port); - Logger.log(`🚀 Application is running on: ${gatewayConfig.host}:${port}`); + Logger.log(`🚀 Application is running on: ${host}:${port}`); } bootstrap(); diff --git a/apps/users-application/src/app/app.module.ts b/apps/users-application/src/app/app.module.ts index df8a77d..9d99bd8 100644 --- a/apps/users-application/src/app/app.module.ts +++ b/apps/users-application/src/app/app.module.ts @@ -1,11 +1,19 @@ +import { userAppConfig } from '@libs/config'; import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { UsersModule } from '../users/users.module'; @Module({ - imports: [UsersModule], + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + load: [userAppConfig], + }), + UsersModule, + ], controllers: [AppController], providers: [AppService], }) diff --git a/apps/users-application/src/main.ts b/apps/users-application/src/main.ts index 720a641..f7c50ce 100644 --- a/apps/users-application/src/main.ts +++ b/apps/users-application/src/main.ts @@ -4,17 +4,21 @@ */ import { Logger } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; import { NestFactory } from '@nestjs/core'; -import { userSubGraph } from '@graphql-federation-workspace/applications-config'; import { AppModule } from './app/app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); - const port = userSubGraph.port; + + const configService = app.get(ConfigService); + const config = configService.get('userApp'); + const host = config.host; + const port = config.port; await app.listen(port); - Logger.log(`🚀 Application is running on: ${userSubGraph.host}:${port}`); + Logger.log(`🚀 Application is running on: ${host}:${port}`); } bootstrap(); diff --git a/libs/config/src/index.ts b/libs/config/src/index.ts index 7e0686c..e41b14c 100644 --- a/libs/config/src/index.ts +++ b/libs/config/src/index.ts @@ -1,3 +1,2 @@ export * from './lib/applications.config'; export * from './lib/database.config'; - From ae34fe370d9fe21040547586f6ef5d4dd97e4724 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 13 Nov 2024 14:14:26 +0900 Subject: [PATCH 4/8] =?UTF-8?q?fix:=20=F0=9F=90=9B=20Add=20type=20safety?= =?UTF-8?q?=20and=20validation=20for=20database=20configuration?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/config/src/lib/database.config.ts | 20 ++++++++++++++++---- package.json | 3 ++- pnpm-lock.yaml | 8 ++++++++ 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/libs/config/src/lib/database.config.ts b/libs/config/src/lib/database.config.ts index f3be4ac..647a408 100644 --- a/libs/config/src/lib/database.config.ts +++ b/libs/config/src/lib/database.config.ts @@ -1,6 +1,18 @@ import { registerAs } from '@nestjs/config'; +import { z } from 'zod'; -export const databaseConfig = registerAs('database', () => ({ - host: process.env['DATABASE_HOST'], - port: process.env['DATABASE_PORT'] || 5432, -})); +const databaseSchema = z.object({ + host: z.string().min(1), + port: z.coerce.number().int().min(1).max(65535), +}); + +export type DatabaseConfig = z.infer; + +export const databaseConfig = registerAs('database', () => { + const config = { + host: process.env['DATABASE_HOST'], + port: process.env['DATABASE_PORT'] || 5432, + }; + + return databaseSchema.parse(config); +}); diff --git a/package.json b/package.json index 7d43631..aead434 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "graphql-tools": "^9.0.2", "inlineTrace": "link:@apollo/server/plugin/inlineTrace", "reflect-metadata": "^0.2.0", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "zod": "^3.23.8" }, "devDependencies": { "@eslint/js": "^9.14.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ef137c..54934f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,9 @@ importers: rxjs: specifier: ^7.8.1 version: 7.8.1 + zod: + specifier: ^3.23.8 + version: 3.23.8 devDependencies: '@eslint/js': specifier: ^9.14.0 @@ -5924,6 +5927,9 @@ packages: zen-observable@0.8.15: resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==} + zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + snapshots: '@adobe/css-tools@4.3.3': {} @@ -12772,3 +12778,5 @@ snapshots: zen-observable@0.8.15: optional: true + + zod@3.23.8: {} From 8ed52c5d74efaa45059df8faece96444182f7251 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 13 Nov 2024 14:22:40 +0900 Subject: [PATCH 5/8] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20add=20prot?= =?UTF-8?q?ocol?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.sample | 8 +-- apps/gateway/src/app/app.module.ts | 2 +- apps/gateway/src/main.ts | 10 ++-- apps/users-application/src/main.ts | 8 +-- .../src/lib/applications.config.spec.ts | 52 +++++++++++++------ libs/config/src/lib/applications.config.ts | 6 ++- 6 files changed, 55 insertions(+), 31 deletions(-) diff --git a/.env.sample b/.env.sample index 215f993..23d26e2 100644 --- a/.env.sample +++ b/.env.sample @@ -1,10 +1,12 @@ -GATEWAY_HOST=http://localhost +PROTOCOL=http + +GATEWAY_HOST=localhost GATEWAY_PORT=3333 -USER_HOST=http://localhost +USER_HOST=localhost USER_PORT=15001 -TASK_HOST=http://localhost +TASK_HOST=localhost TASK_PORT=15002 DATABASE_USER=test diff --git a/apps/gateway/src/app/app.module.ts b/apps/gateway/src/app/app.module.ts index 1e0e9c7..80c1e35 100644 --- a/apps/gateway/src/app/app.module.ts +++ b/apps/gateway/src/app/app.module.ts @@ -27,7 +27,7 @@ import { AppService } from './app.service'; subgraphs: [ { name: userAppConfig.name, - url: `${userAppConfig.host}:${userAppConfig.port}/graphql`, + url: `${userAppConfig.protocol}://${userAppConfig.host}:${userAppConfig.port}/graphql`, }, ], }), diff --git a/apps/gateway/src/main.ts b/apps/gateway/src/main.ts index 10666c2..1e16adf 100644 --- a/apps/gateway/src/main.ts +++ b/apps/gateway/src/main.ts @@ -11,14 +11,14 @@ import { AppModule } from './app/app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); - + const configService = app.get(ConfigService); const config = configService.get('gateway'); - const host = config.host; - const port = config.port; - await app.listen(port); - Logger.log(`🚀 Application is running on: ${host}:${port}`); + await app.listen(config.port); + Logger.log( + `🚀 Application is running on: ${config.protocol}://${config.host}:${config.port}`, + ); } bootstrap(); diff --git a/apps/users-application/src/main.ts b/apps/users-application/src/main.ts index f7c50ce..e10bcd8 100644 --- a/apps/users-application/src/main.ts +++ b/apps/users-application/src/main.ts @@ -14,11 +14,11 @@ async function bootstrap() { const configService = app.get(ConfigService); const config = configService.get('userApp'); - const host = config.host; - const port = config.port; - await app.listen(port); - Logger.log(`🚀 Application is running on: ${host}:${port}`); + await app.listen(config.port); + Logger.log( + ` 🚀 Application is running on: ${config.protocol}://${config.host}:${config.port}`, + ); } bootstrap(); diff --git a/libs/config/src/lib/applications.config.spec.ts b/libs/config/src/lib/applications.config.spec.ts index b35fc0d..5628a4b 100644 --- a/libs/config/src/lib/applications.config.spec.ts +++ b/libs/config/src/lib/applications.config.spec.ts @@ -4,16 +4,26 @@ describe('Config Tests', () => { describe('gatewayConfig', () => { it('should return default values when environment variables are not set', () => { const config = gatewayConfig(); - expect(config.host).toBe('http://localhost'); - expect(config.port).toBe('3333'); + expect(config).toEqual({ + protocol: 'http', + host: 'localhost', + port: '3333', + }); }); - it('should return environment values when environment variables are set', () => { - process.env['GATEWAY_HOST'] = 'http://gateway-host'; - process.env['GATEWAY_PORT'] = '4000'; + it('should return environment variable values when they are set', () => { + process.env['PROTOCOL'] = 'https'; + process.env['GATEWAY_HOST'] = 'gateway.example.com'; + process.env['GATEWAY_PORT'] = '4444'; + const config = gatewayConfig(); - expect(config.host).toBe('http://gateway-host'); - expect(config.port).toBe('4000'); + expect(config).toEqual({ + protocol: 'https', + host: 'gateway.example.com', + port: '4444', + }); + + delete process.env['PROTOCOL']; delete process.env['GATEWAY_HOST']; delete process.env['GATEWAY_PORT']; }); @@ -22,18 +32,28 @@ describe('Config Tests', () => { describe('userAppConfig', () => { it('should return default values when environment variables are not set', () => { const config = userAppConfig(); - expect(config.host).toBe('http://localhost'); - expect(config.port).toBe('15001'); - expect(config.name).toBe('user'); + expect(config).toEqual({ + protocol: 'http', + host: 'localhost', + port: '15001', + name: 'user', + }); }); - it('should return environment values when environment variables are set', () => { - process.env['USER_HOST'] = 'http://user-host'; - process.env['USER_PORT'] = '5000'; + it('should return environment variable values when they are set', () => { + process.env['PROTOCOL'] = 'https'; + process.env['USER_HOST'] = 'user.example.com'; + process.env['USER_PORT'] = '5555'; + const config = userAppConfig(); - expect(config.host).toBe('http://user-host'); - expect(config.port).toBe('5000'); - expect(config.name).toBe('user'); + expect(config).toEqual({ + protocol: 'https', + host: 'user.example.com', + port: '5555', + name: 'user', + }); + + delete process.env['PROTOCOL']; delete process.env['USER_HOST']; delete process.env['USER_PORT']; }); diff --git a/libs/config/src/lib/applications.config.ts b/libs/config/src/lib/applications.config.ts index d8655dd..7aafa77 100644 --- a/libs/config/src/lib/applications.config.ts +++ b/libs/config/src/lib/applications.config.ts @@ -1,7 +1,7 @@ import { registerAs } from '@nestjs/config'; -const DEFAULT_HOST = 'http://localhost'; - +const DEFAULT_PROTOCOL = 'http'; +const DEFAULT_HOST = 'localhost'; const DEFAULT_PORT = { user: '15001', task: '15002', @@ -9,11 +9,13 @@ const DEFAULT_PORT = { }; export const gatewayConfig = registerAs('gateway', () => ({ + protocol: process.env['PROTOCOL'] ?? DEFAULT_PROTOCOL, host: process.env['GATEWAY_HOST'] ?? DEFAULT_HOST, port: process.env['GATEWAY_PORT'] ?? DEFAULT_PORT.gateway, })); export const userAppConfig = registerAs('userApp', () => ({ + protocol: process.env['PROTOCOL'] ?? DEFAULT_PROTOCOL, host: process.env['USER_HOST'] ?? DEFAULT_HOST, port: process.env['USER_PORT'] ?? DEFAULT_PORT.user, name: 'user', From 0aac0d7ad51df966cf261659883a1fa63b7b4fcb Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 13 Nov 2024 14:24:46 +0900 Subject: [PATCH 6/8] =?UTF-8?q?fix:=20=F0=9F=90=9B=20Update=20configuratio?= =?UTF-8?q?n=20object=20with=20credentials?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.sample | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.sample b/.env.sample index 23d26e2..6c2a63b 100644 --- a/.env.sample +++ b/.env.sample @@ -9,5 +9,5 @@ USER_PORT=15001 TASK_HOST=localhost TASK_PORT=15002 -DATABASE_USER=test -DATABASE_PASSWORD=test +DATABASE_HOST=127.0.0.1 +DATABASE_PORT=3306 From 66c068145661662074fe892e6c542eb89906cd00 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 13 Nov 2024 14:31:38 +0900 Subject: [PATCH 7/8] =?UTF-8?q?test:=20=F0=9F=A7=AA=20test=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/config/src/lib/database.config.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/config/src/lib/database.config.spec.ts b/libs/config/src/lib/database.config.spec.ts index 28b87f6..123b341 100644 --- a/libs/config/src/lib/database.config.spec.ts +++ b/libs/config/src/lib/database.config.spec.ts @@ -18,7 +18,7 @@ describe('databaseConfig', () => { const config = databaseConfig(); expect(config.host).toBe('localhost'); - expect(config.port).toBe('3306'); + expect(config.port).toBe(3306); }); it('should return the default port if DATABASE_PORT is not set', () => { From bb73162dac6189b571c93bc61007d99d346c42a4 Mon Sep 17 00:00:00 2001 From: zhumeisongsong Date: Wed, 13 Nov 2024 15:21:56 +0900 Subject: [PATCH 8/8] =?UTF-8?q?fix:=20=F0=9F=90=9B=20port=20string=20to=20?= =?UTF-8?q?number?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/lib/applications.config.spec.ts | 16 +++--- libs/config/src/lib/applications.config.ts | 51 ++++++++++++------- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/libs/config/src/lib/applications.config.spec.ts b/libs/config/src/lib/applications.config.spec.ts index 5628a4b..d7f9532 100644 --- a/libs/config/src/lib/applications.config.spec.ts +++ b/libs/config/src/lib/applications.config.spec.ts @@ -2,16 +2,16 @@ import { gatewayConfig, userAppConfig } from './applications.config'; describe('Config Tests', () => { describe('gatewayConfig', () => { - it('should return default values when environment variables are not set', () => { + it('should return default gateway config when no environment variables are set', () => { const config = gatewayConfig(); expect(config).toEqual({ protocol: 'http', host: 'localhost', - port: '3333', + port: 3333, }); }); - it('should return environment variable values when they are set', () => { + it('should return gateway config with environment variables', () => { process.env['PROTOCOL'] = 'https'; process.env['GATEWAY_HOST'] = 'gateway.example.com'; process.env['GATEWAY_PORT'] = '4444'; @@ -20,7 +20,7 @@ describe('Config Tests', () => { expect(config).toEqual({ protocol: 'https', host: 'gateway.example.com', - port: '4444', + port: 4444, }); delete process.env['PROTOCOL']; @@ -30,17 +30,17 @@ describe('Config Tests', () => { }); describe('userAppConfig', () => { - it('should return default values when environment variables are not set', () => { + it('should return default user app config when no environment variables are set', () => { const config = userAppConfig(); expect(config).toEqual({ protocol: 'http', host: 'localhost', - port: '15001', + port: 15001, name: 'user', }); }); - it('should return environment variable values when they are set', () => { + it('should return user app config with environment variables', () => { process.env['PROTOCOL'] = 'https'; process.env['USER_HOST'] = 'user.example.com'; process.env['USER_PORT'] = '5555'; @@ -49,7 +49,7 @@ describe('Config Tests', () => { expect(config).toEqual({ protocol: 'https', host: 'user.example.com', - port: '5555', + port: 5555, name: 'user', }); diff --git a/libs/config/src/lib/applications.config.ts b/libs/config/src/lib/applications.config.ts index 7aafa77..8c0c2ea 100644 --- a/libs/config/src/lib/applications.config.ts +++ b/libs/config/src/lib/applications.config.ts @@ -1,22 +1,39 @@ import { registerAs } from '@nestjs/config'; -const DEFAULT_PROTOCOL = 'http'; -const DEFAULT_HOST = 'localhost'; +interface ServiceConfig { + protocol: string; + host: string; + port: number; + name?: string; +} + +const DEFAULT_PROTOCOL = 'http' as const; +const DEFAULT_HOST = 'localhost' as const; const DEFAULT_PORT = { - user: '15001', - task: '15002', - gateway: '3333', -}; + user: 15001, + task: 15002, + gateway: 3333, +} as const; -export const gatewayConfig = registerAs('gateway', () => ({ - protocol: process.env['PROTOCOL'] ?? DEFAULT_PROTOCOL, - host: process.env['GATEWAY_HOST'] ?? DEFAULT_HOST, - port: process.env['GATEWAY_PORT'] ?? DEFAULT_PORT.gateway, -})); +export const gatewayConfig = registerAs( + 'gateway', + (): ServiceConfig => ({ + protocol: process.env['PROTOCOL'] ?? DEFAULT_PROTOCOL, + host: process.env['GATEWAY_HOST'] ?? DEFAULT_HOST, + port: process.env['GATEWAY_PORT'] + ? Number(process.env['GATEWAY_PORT']) + : DEFAULT_PORT.gateway, + }), +); -export const userAppConfig = registerAs('userApp', () => ({ - protocol: process.env['PROTOCOL'] ?? DEFAULT_PROTOCOL, - host: process.env['USER_HOST'] ?? DEFAULT_HOST, - port: process.env['USER_PORT'] ?? DEFAULT_PORT.user, - name: 'user', -})); +export const userAppConfig = registerAs( + 'userApp', + (): ServiceConfig => ({ + protocol: process.env['PROTOCOL'] ?? DEFAULT_PROTOCOL, + host: process.env['USER_HOST'] ?? DEFAULT_HOST, + port: process.env['USER_PORT'] + ? Number(process.env['USER_PORT']) + : DEFAULT_PORT.user, + name: 'user', + }), +);