diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..8ac643e --- /dev/null +++ b/.env.sample @@ -0,0 +1,8 @@ +GATEWAY_HOST=localhost +GATEWAY_PORT=3333 + +USER_HOST=localhost +USER_PORT=15001 + +TASK_HOST=localhost +TASK_PORT=15002 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4f4d87b..790cf0f 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,6 @@ Thumbs.db .nx/cache .nx/workspace-data + +.env +.env.local diff --git a/apps/gateway-e2e/src/gateway/gateway.spec.ts b/apps/gateway-e2e/src/gateway/gateway.spec.ts index e8ac2a6..63b0b59 100644 --- a/apps/gateway-e2e/src/gateway/gateway.spec.ts +++ b/apps/gateway-e2e/src/gateway/gateway.spec.ts @@ -1,10 +1,10 @@ import axios from 'axios'; -describe('GET /api', () => { +describe('GET /', () => { it('should return a message', async () => { - const res = await axios.get(`/api`); + const res = await axios.get(`/`); expect(res.status).toBe(200); - expect(res.data).toEqual({ message: 'Hello API' }); + expect(res.data).toEqual({ message: 'Hello Gateway' }); }); }); diff --git a/apps/gateway-e2e/src/support/test-setup.ts b/apps/gateway-e2e/src/support/test-setup.ts index 07f2870..ae6198b 100644 --- a/apps/gateway-e2e/src/support/test-setup.ts +++ b/apps/gateway-e2e/src/support/test-setup.ts @@ -5,6 +5,6 @@ import axios from 'axios'; module.exports = async function () { // Configure axios for tests to use. const host = process.env.HOST ?? 'localhost'; - const port = process.env.PORT ?? '3000'; + const port = process.env.PORT ?? '3333'; axios.defaults.baseURL = `http://${host}:${port}`; }; diff --git a/apps/gateway/src/app/app.controller.spec.ts b/apps/gateway/src/app/app.controller.spec.ts index de8007e..1462413 100644 --- a/apps/gateway/src/app/app.controller.spec.ts +++ b/apps/gateway/src/app/app.controller.spec.ts @@ -14,9 +14,9 @@ describe('AppController', () => { }); describe('getData', () => { - it('should return "Hello API"', () => { + it('should return "Hello Gateway"', () => { const appController = app.get(AppController); - expect(appController.getData()).toEqual({ message: 'Hello API' }); + expect(appController.getData()).toEqual({ message: 'Hello Gateway' }); }); }); }); diff --git a/apps/gateway/src/app/app.service.spec.ts b/apps/gateway/src/app/app.service.spec.ts index 42cf0a2..e43c635 100644 --- a/apps/gateway/src/app/app.service.spec.ts +++ b/apps/gateway/src/app/app.service.spec.ts @@ -14,8 +14,8 @@ describe('AppService', () => { }); describe('getData', () => { - it('should return "Hello API"', () => { - expect(service.getData()).toEqual({ message: 'Hello API' }); + it('should return "Hello Gateway"', () => { + expect(service.getData()).toEqual({ message: 'Hello Gateway' }); }); }); }); diff --git a/apps/gateway/src/app/app.service.ts b/apps/gateway/src/app/app.service.ts index cd8cede..bcea422 100644 --- a/apps/gateway/src/app/app.service.ts +++ b/apps/gateway/src/app/app.service.ts @@ -3,6 +3,6 @@ import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getData(): { message: string } { - return { message: 'Hello API' }; + return { message: 'Hello Gateway' }; } } diff --git a/apps/gateway/src/main.ts b/apps/gateway/src/main.ts index a124382..b25b640 100644 --- a/apps/gateway/src/main.ts +++ b/apps/gateway/src/main.ts @@ -5,17 +5,17 @@ import { Logger } from '@nestjs/common'; 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 globalPrefix = 'api'; - app.setGlobalPrefix(globalPrefix); - const port = process.env.PORT || 3000; + const port = gatewayConfig.port; + await app.listen(port); Logger.log( - `🚀 Application is running on: http://localhost:${port}/${globalPrefix}` + `🚀 Application is running on: http://${gatewayConfig.host}:${port}` ); } diff --git a/apps/users-application-e2e/src/support/test-setup.ts b/apps/users-application-e2e/src/support/test-setup.ts index 07f2870..6cfc4b0 100644 --- a/apps/users-application-e2e/src/support/test-setup.ts +++ b/apps/users-application-e2e/src/support/test-setup.ts @@ -5,6 +5,6 @@ import axios from 'axios'; module.exports = async function () { // Configure axios for tests to use. const host = process.env.HOST ?? 'localhost'; - const port = process.env.PORT ?? '3000'; + const port = process.env.PORT ?? '15001'; axios.defaults.baseURL = `http://${host}:${port}`; }; diff --git a/apps/users-application-e2e/src/users-application/users-application.spec.ts b/apps/users-application-e2e/src/users-application/users-application.spec.ts index e8ac2a6..b33e9ba 100644 --- a/apps/users-application-e2e/src/users-application/users-application.spec.ts +++ b/apps/users-application-e2e/src/users-application/users-application.spec.ts @@ -1,10 +1,10 @@ import axios from 'axios'; -describe('GET /api', () => { +describe('GET /', () => { it('should return a message', async () => { - const res = await axios.get(`/api`); + const res = await axios.get(`/`); expect(res.status).toBe(200); - expect(res.data).toEqual({ message: 'Hello API' }); + expect(res.data).toEqual({ message: 'Hello User Service' }); }); }); diff --git a/apps/users-application/src/app/app.controller.spec.ts b/apps/users-application/src/app/app.controller.spec.ts index de8007e..e089b7a 100644 --- a/apps/users-application/src/app/app.controller.spec.ts +++ b/apps/users-application/src/app/app.controller.spec.ts @@ -14,9 +14,9 @@ describe('AppController', () => { }); describe('getData', () => { - it('should return "Hello API"', () => { + it('should return "Hello User Service"', () => { const appController = app.get(AppController); - expect(appController.getData()).toEqual({ message: 'Hello API' }); + expect(appController.getData()).toEqual({ message: 'Hello User Service' }); }); }); }); diff --git a/apps/users-application/src/app/app.service.spec.ts b/apps/users-application/src/app/app.service.spec.ts index 42cf0a2..e9eea2e 100644 --- a/apps/users-application/src/app/app.service.spec.ts +++ b/apps/users-application/src/app/app.service.spec.ts @@ -14,8 +14,8 @@ describe('AppService', () => { }); describe('getData', () => { - it('should return "Hello API"', () => { - expect(service.getData()).toEqual({ message: 'Hello API' }); + it('should return "Hello User Service"', () => { + expect(service.getData()).toEqual({ message: 'Hello User Service' }); }); }); }); diff --git a/apps/users-application/src/app/app.service.ts b/apps/users-application/src/app/app.service.ts index cd8cede..b0af72b 100644 --- a/apps/users-application/src/app/app.service.ts +++ b/apps/users-application/src/app/app.service.ts @@ -3,6 +3,6 @@ import { Injectable } from '@nestjs/common'; @Injectable() export class AppService { getData(): { message: string } { - return { message: 'Hello API' }; + return { message: 'Hello User Service' }; } } diff --git a/apps/users-application/src/main.ts b/apps/users-application/src/main.ts index a124382..73c159b 100644 --- a/apps/users-application/src/main.ts +++ b/apps/users-application/src/main.ts @@ -5,17 +5,17 @@ import { Logger } from '@nestjs/common'; 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 globalPrefix = 'api'; - app.setGlobalPrefix(globalPrefix); - const port = process.env.PORT || 3000; + const port = userSubGraph.port; + await app.listen(port); Logger.log( - `🚀 Application is running on: http://localhost:${port}/${globalPrefix}` + `🚀 Application is running on: http://${userSubGraph.host}:${port}` ); } diff --git a/libs/application-config/README.md b/libs/application-config/README.md new file mode 100644 index 0000000..6494920 --- /dev/null +++ b/libs/application-config/README.md @@ -0,0 +1,7 @@ +# applications-config + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test applications-config` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/application-config/eslint.config.js b/libs/application-config/eslint.config.js new file mode 100644 index 0000000..df7cfc2 --- /dev/null +++ b/libs/application-config/eslint.config.js @@ -0,0 +1,3 @@ +const baseConfig = require('../../eslint.config.js'); + +module.exports = [...baseConfig]; diff --git a/libs/application-config/jest.config.ts b/libs/application-config/jest.config.ts new file mode 100644 index 0000000..a7ffe20 --- /dev/null +++ b/libs/application-config/jest.config.ts @@ -0,0 +1,10 @@ +export default { + displayName: 'applications-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', +}; diff --git a/libs/application-config/project.json b/libs/application-config/project.json new file mode 100644 index 0000000..54220f1 --- /dev/null +++ b/libs/application-config/project.json @@ -0,0 +1,9 @@ +{ + "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 new file mode 100644 index 0000000..f4ec158 --- /dev/null +++ b/libs/application-config/src/index.ts @@ -0,0 +1 @@ +export * from './lib/applications-config'; diff --git a/libs/application-config/src/lib/applications-config.spec.ts b/libs/application-config/src/lib/applications-config.spec.ts new file mode 100644 index 0000000..72939b6 --- /dev/null +++ b/libs/application-config/src/lib/applications-config.spec.ts @@ -0,0 +1,67 @@ +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: 'localhost', + port: '3333', + }); + + expect(userSubGraph).toEqual({ + host: 'localhost', + port: '15001', + }); + + expect(taskSubGraph).toEqual({ + host: 'localhost', + 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', + port: '4000', + }); + + expect(userSubGraph).toEqual({ + host: 'user.example.com', + port: '5000', + }); + + expect(taskSubGraph).toEqual({ + host: 'task.example.com', + port: '6000', + }); + }); +}); diff --git a/libs/application-config/src/lib/applications-config.ts b/libs/application-config/src/lib/applications-config.ts new file mode 100644 index 0000000..4b6e66b --- /dev/null +++ b/libs/application-config/src/lib/applications-config.ts @@ -0,0 +1,29 @@ +interface ApplicationConfig { + host: string; + port: string; +} + +const DEFAULT_HOST = '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, +}; + +// Graphql +export const userSubGraph: ApplicationConfig = { + host: process.env['USER_HOST'] ?? DEFAULT_HOST, + port: process.env['USER_PORT'] ?? DEFAULT_PORT.user, +}; + +export const taskSubGraph: ApplicationConfig = { + host: process.env['TASK_HOST'] ?? DEFAULT_HOST, + port: process.env['TASK_PORT'] ?? DEFAULT_PORT.task, +}; diff --git a/libs/application-config/tsconfig.json b/libs/application-config/tsconfig.json new file mode 100644 index 0000000..6f7169a --- /dev/null +++ b/libs/application-config/tsconfig.json @@ -0,0 +1,22 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "commonjs", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noPropertyAccessFromIndexSignature": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/application-config/tsconfig.lib.json b/libs/application-config/tsconfig.lib.json new file mode 100644 index 0000000..3f06e80 --- /dev/null +++ b/libs/application-config/tsconfig.lib.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "outDir": "../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/libs/application-config/tsconfig.spec.json b/libs/application-config/tsconfig.spec.json new file mode 100644 index 0000000..9b2a121 --- /dev/null +++ b/libs/application-config/tsconfig.spec.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index b73cce6..70deefe 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -14,7 +14,11 @@ "skipLibCheck": true, "skipDefaultLibCheck": true, "baseUrl": ".", - "paths": {} + "paths": { + "@graphql-federation-workspace/applications-config": [ + "libs/application-config/src/index.ts" + ] + } }, "exclude": ["node_modules", "tmp"] }