Documentation chapters
You're looking at legacy documentation.
New multi-language documentation available at https://docs.deepkit.io
Framework

Configuration

In Deepkit Framework modules and your application can have configuration options. A configuration could be database urls, passwords, IPs, and so on. Services and controllers can read those configuration options via dependency injection.

A configuration can be defined by defining a class with properties. It is a typesafe way to define a configuration for your whole application and its values are automatically serialized and validated.

#!/usr/bin/env ts-node-script
import { App } from '@deepkit/app';
import { FrameworkModule } from '@deepkit/framework';
import { t } from '@deepkit/type';
import { inject } from '@deepkit/injector';
import { http } from '@deepkit/http';

class Config {
    pageTitle: string = 'Cool site';
    domain: string = 'example.com';
    debug: boolean = false;
}

class MyWebsite {
    constructor(
        protected allSettings: Config
    ) {
    }

    @http.GET()
    helloWorld() {
        return 'Hello from ' + this.allSettings.pageTitle + ' via ' + this.allSettings.domain;
    }
}

new App({
    config: Config,
    controllers: [MyWebsite],
    imports: [new FrameworkModule]
}).run();
$ curl http://localhost:8080/
Hello from Cool site via example.com

There are several ways to read those configuration values in your services and controllers.

Configuration option

You can inject a single configuration option by using the TypeScript index access type operator.

import { http } from '@deepkit/http';
import { Config } from './app-config.ts';

class MyWebsite {
    constructor(pageTitle: Config['pageTitle']) {
    }
}

Configuration partial

To inject a partial configuration object, use the Pick TypeScript type function.

import { Config } from './app-config.ts';

type WebsiteSettings = Pick<Config, 'pageTitle' | 'domain'>

class MyWebsite {
    constructor(protected settings: WebsiteSettings) {}
    //or
    // constructor(protected settings: Pick<Config, 'pageTitle' | 'domain'>) {}

    @http.GET()
    helloWorld() {
        return 'Hello from ' + this.settings.pageTitle;
    }
}

In unit tests you have to provide only the options you picked. The type itself comes from your configuration class.

import { MyWebsite } from './app-config.ts';

test('website', async () => {
    const website = new MyWebsite({pageTitle: 'World'});

    expect(website.helloWorld()).toBe('Hello from World');
});

All configuration options

Another option is to inject the whole configuration object.

import { Config } from './app-config.ts';

class MyWebsite {
    constructor(protected settings: Config) {
    }

    @http.GET()
    helloWorld() {
        return 'Hello from ' + this.settings.pageTitle;
    }
}

Configuration schema

The configuration schema is a simple class with type definitions. It allows your to define descriptions and validations.

export class Config {
    pageTitle: string = 'Cool site';

    domain: string = 'example.com';
    port: number = 8080;
    databaseUrl: string = 'mongodb://localhost/';
    
    email: boolean = false;
    emailServer?: string;

    requiredValue!: string;
}

Validation

All correctly typed properties are automatically validated in the bootstrap phase before any service is instantiated.

Required properties with the ! are required and need to be provided or else the configuration validation fails. Also adding validators from @deepkit/type allows your to further validate the configuration values before they are used.

import { Validate, MinLength, ValidatorError } from '@deepkit/type';

function emailValidation(value: any) {
    if ('string' === typeof value && value.test(/^\[email protected]\S+$/) return;
    return new ValidatorError('email', 'Not an email');
}

export class Config {
    /**
     * @description this is a description that shows up in app:config command.
     */
    pageTitle: string & MinLength<3> = 'Cool site';
    emailServer?: string & Validate<typeof emailValidation>;
}

See the @deepkit/type validation documentation for more information.

Debugger

Configuration values of your application and all modules can be shown in the debugger. Activate the debug option in the FrameworkModule and open http://localhost:8080/_debug/configuration.

import { App } from '@deepkit/app';
import { FrameworkModule } from '@deepkit/framework';

new App({
    config: Config,
    controllers: [MyWebsite],
    imports: [
        new FrameworkModule({
            debug: true,
        })
    ]
}).run();

You can also use ts-node app.ts app:config to see all available configuration options, active default, their default value, description and data type.

$ ts-node app.ts app:config
Application config
┌─────────┬───────────────┬────────────────────────┬────────────────────────┬─────────────┬───────────┐
│ (index) │     name      │         value          │      defaultValue      │ description │   type    │
├─────────┼───────────────┼────────────────────────┼────────────────────────┼─────────────┼───────────┤
│    0    │  'pageTitle'  │     'Other title'      │      'Cool site'       │     ''      │ 'string'  │
│    1    │   'domain'    │     'example.com'      │     'example.com'      │     ''      │ 'string'  │
│    2    │    'port'     │          8080          │          8080          │     ''      │ 'number'  │
│    3    │ 'databaseUrl' │ 'mongodb://localhost/' │ 'mongodb://localhost/' │     ''      │ 'string'  │
│    4    │    'email'    │         false          │         false          │     ''      │ 'boolean' │
│    5    │ 'emailSender' │       undefined        │       undefined        │     ''      │ 'string?' │
└─────────┴───────────────┴────────────────────────┴────────────────────────┴─────────────┴───────────┘
Modules config
┌─────────┬──────────────────────────────┬─────────────────┬─────────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────┬────────────┐
│ (index) │           name               │      value      │  defaultValue   │                                            description                                             │    type    │
├─────────┼──────────────────────────────┼─────────────────┼─────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────┼────────────┤
│    0    │       'framework.host'       │   'localhost'   │   'localhost'   │                                                 ''                                                 │  'string'  │
│    1    │       'framework.port'       │      8080       │      8080       │                                                 ''                                                 │  'number'  │
│    2    │    'framework.httpsPort'     │    undefined    │    undefined    │ 'If httpsPort and ssl is defined, then the https server is started additional to the http-server.' │ 'number?'  │
│    3    │    'framework.selfSigned'    │    undefined    │    undefined    │           'If for ssl: true the certificate and key should be automatically generated.'            │ 'boolean?' │
│    4    │ 'framework.keepAliveTimeout' │    undefined    │    undefined    │                                                 ''                                                 │ 'number?'  │
│    5    │       'framework.path'       │       '/'       │       '/'       │                                                 ''                                                 │  'string'  │
│    6    │     'framework.workers'      │        1        │        1        │                                                 ''                                                 │  'number'  │
│    7    │       'framework.ssl'        │      false      │      false      │                                       'Enables HTTPS server'                                       │ 'boolean'  │
│    8    │    'framework.sslOptions'    │    undefined    │    undefined    │                   'Same interface as tls.SecureContextOptions & tls.TlsOptions.'                   │   'any'    │
...

Set configuration values

Per default no values are overwritten, so default values are used. There are several ways to set configuration values.

  • Environment variables for each option
  • Environment variable via JSON
  • dotenv files

You can use multiple configuration loading methods at the same time. The order in which they are called is important.

Environment variables

To allow setting each configuration option via its own environment variable, use loadConfigFromEnv. The default prefix is APP_, but you can change tht. It also loads automatically .env files. Per default a uppercase naming strategy is used, but you can change that as well.

For configuration options like above pageTitle, you can use APP_PAGE_TITLE="Other title".

new App({
    config: config,
    controllers: [MyWebsite],
})
    .loadConfigFromEnv()
    .run();
APP_PAGE_TITLE="Other title" ts-node app.ts server:start

JSON environment variable

To change multiple configuration options via a single environment variable, use loadConfigFromEnvVariable. The first argument is its environment variable name.

new App({
    config: config,
    controllers: [MyWebsite],
})
    .loadConfigFromEnvVariable('APP_CONFIG')
    .run();
APP_CONFIG='{"pageTitle": "Other title"}' ts-node app.ts server:start

DotEnv files

To change multiple configuration options via a dotenv file, use loadConfigFromEnv. The first argument is either a path to a dot env (relative to cwd) or multiple paths. If its an array it tries each path until it finds an existing file.

new App({
    config: config,
    controllers: [MyWebsite],
})
    .loadConfigFromEnv({envFilePath: ['production.dotenv', 'dotenv']})
    .run();
$ cat dotenv
APP_PAGE_TITLE=Other title
$ ts-node app.ts server:start

Configure module

Each imported module can have a module name. This name is used for the configuration paths used above.

For environment variable configuration the path for example for the FrameworkModule option port is FRAMEWORK_PORT. All names are per default upper-case. If a prefix of APP_ is used you can change the port via:

$ APP_FRAMEWORK_PORT=9999 ts-node app.ts server:start
2021-06-12T18:59:26.363Z [LOG] Start HTTP server, using 1 workers.
2021-06-12T18:59:26.365Z [LOG] HTTP MyWebsite
2021-06-12T18:59:26.366Z [LOG]     GET / helloWorld
2021-06-12T18:59:26.366Z [LOG] HTTP listening at http://localhost:9999/

In dotenv files it would be APP_FRAMEWORK_PORT=9999 too.

In JSON environment variables via loadConfigFromEnvVariable('APP_CONFIG') on the other hand its the structure of the actual configuration class. framework becomes an object.

$ APP_CONFIG='{"framework": {"port": 9999}}' ts-node app.ts server:start

This works the same for all modules. For configuration option of your application there is no module prefix needed.

Made in Germany