Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server)!: add support for env variables in the configuration #455

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/nodejsci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:

strategy:
matrix:
node-version: [18.x, 19.x, 20.x, 21.x]
node-version: [20.x, 21.x]

steps:
- uses: actions/checkout@v4
Expand Down
15 changes: 12 additions & 3 deletions documentation/docs/fundamentals/runtime-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ Configurations are placed in JSON files. The basic structure looks like this.
}
```

::: tip NOTE
The configuration also supports environment variables. They can be used by wrapping the variable name in `${}`. For example, `${ENVIRONMENT_VARIABLE_1}`.
```json
{
"PROPERTY_3": "${ENVIRONMENT_VARIABLE_3}"
}
```
:::

There are four properties at root level:

* url - service url containing protocol, address and port (e.g. `http://service.example.com:3000`).
Expand Down Expand Up @@ -128,7 +137,7 @@ A full configuration example looks like this:
"repository": "http://repository.example.com:3000",
"segments": ["segment1", "segment2"],
"middlewares": ["./middleware1", "./middleware2"],
"trustKey": "MY_TRUST_KEY"
"trustKey": "${MY_TRUST_KEY}"
}
}
```
Expand Down Expand Up @@ -176,7 +185,7 @@ A full configuration example looks like this:
"repository": "http://repository.example.com:3000",
"monitor": 5000,
"middlewares": ["./middleware1", "./middleware2"],
"trustKey": "MY_TRUST_KEY"
"trustKey": "${MY_TRUST_KEY}"
}
}
```
Expand Down Expand Up @@ -252,7 +261,7 @@ A full configuration example looks like this:
"assets": ["*.html", "*.js", "*.css", "assets/**/*"],
"middlewares": ["./middleware1", "./middleware2"],
"overrides": { "./my-module": "./alternative-module" },
"trustKey": "MY_TRUST_KEY"
"trustKey": "${MY_TRUST_KEY}"
}
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ In this guide we will explain what needs to be done to add Jitar to your project

A Jitar project has a few requirements to function properly. Before adding Jitar make sure the the following conditions are (or can be) met:

* Node version 18.17.1 or higher
* Node version 20.0 or higher
* TypeScript 4.7 or higher
* Use of ESM (CommonJS is not supported)
* Vite, if a frontend needs to be hooked in
Expand Down
1 change: 1 addition & 0 deletions examples/concepts/access-protection/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TRUST_KEY="MY_VERY_SECRET_KEY"
8 changes: 4 additions & 4 deletions examples/concepts/access-protection/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
"private": true,
"scripts": {
"build": "tsc",
"standalone": "node --experimental-network-imports dist/jitar.js --config=services/standalone.json",
"standalone": "node --experimental-network-imports --env-file=.env dist/jitar.js --config=services/standalone.json",
"repo": "node --experimental-network-imports dist/jitar.js --config=services/repository.json",
"gateway": "node --experimental-network-imports dist/jitar.js --config=services/gateway.json",
"node-web": "node --experimental-network-imports dist/jitar.js --config=services/web.json",
"node-game": "node --experimental-network-imports dist/jitar.js --config=services/game.json"
"gateway": "node --experimental-network-imports --env-file=.env dist/jitar.js --config=services/gateway.json",
"node-web": "node --experimental-network-imports --env-file=.env dist/jitar.js --config=services/web.json",
"node-game": "node --experimental-network-imports --env-file=.env dist/jitar.js --config=services/game.json"
},
"dependencies": {
"jitar": "^0.6.0"
Expand Down
2 changes: 1 addition & 1 deletion examples/concepts/access-protection/services/game.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"gateway": "http://127.0.0.1:3000",
"repository": "http://127.0.0.1:2999",
"segments": [ "protected" ],
"trustKey": "VERY_SECRET_KEY"
"trustKey": "${TRUST_KEY}"
}
}
2 changes: 1 addition & 1 deletion examples/concepts/access-protection/services/gateway.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
"url": "http://127.0.0.1:3000",
"gateway": {
"repository": "http://127.0.0.1:2999",
"trustKey": "VERY_SECRET_KEY"
"trustKey": "${TRUST_KEY}"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
"url": "http://127.0.0.1:3000",
"standalone":
{
"trustKey": "VERY_SECRET_KEY"
"trustKey": "${TRUST_KEY}"
}
}
2 changes: 1 addition & 1 deletion examples/concepts/access-protection/services/web.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
"gateway": "http://127.0.0.1:3000",
"repository": "http://127.0.0.1:2999",
"segments": [ "public" ],
"trustKey": "VERY_SECRET_KEY"
"trustKey": "${TRUST_KEY}"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

export default class EnvironmentVariableNotFound extends Error
{
constructor(name: string)
{
super(`The environment variable '${name}' is not found`);
}
}
22 changes: 21 additions & 1 deletion packages/server-nodejs/src/utils/RuntimeConfigurationLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,35 @@ import { readFileSync } from 'fs';

import RuntimeConfiguration, { runtimeSchema } from '../configuration/RuntimeConfiguration.js';

import EnvironmentVariableNotFound from '../errors/EnvironmentVariableNotFound.js';

import DataConverter from './DataConverter.js';

const ENVIRONMENT_VARIABLE_REGEX = /\${([^}]*)}/g;

export default class RuntimeConfigurationLoader
{
static load(filename: string): RuntimeConfiguration
{
const plainContents = readFileSync(filename, 'utf-8');
const parsedContents = JSON.parse(plainContents);
const replacedContents = this.#replaceEnvValues(plainContents);
const parsedContents = JSON.parse(replacedContents);

return DataConverter.convert<RuntimeConfiguration>(runtimeSchema, parsedContents);
}

static #replaceEnvValues(contents: string): string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use abbreviations 😉

{
return contents.replace(ENVIRONMENT_VARIABLE_REGEX, (match, group) =>
{
const value = process.env[group];

if (value === undefined)
{
throw new EnvironmentVariableNotFound(group);
}

return value;
});
}
}