Configuration

let you to configure quickly your server via decorator. This decorator take your configuration and merge it with the default server configuration.

The default configuration is as following:

{
  "rootDir": "path/to/root/project",
  "env": "development",
  "port": 8080,
  "debug": false,
  "httpsPort": 8000,
  "uploadDir": "${rootDir}/uploads",
  "mount": {
    "/rest": "${rootDir}/controllers/**/*.ts" // support ts with ts-node then fallback to js
  },
  "componentsScan": [
    "${rootDir}/middlewares/**/*.ts",
    "${rootDir}/services/**/*.ts",
    "${rootDir}/converters/**/*.ts"
  ],
  "routers": {
    "mergeParams": false,
    "strict": false,
    "caseSensitive": false
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

You can customize your configuration as followigng on Server.tslevel:

import {ServerLoader, ServerSettings} from "@tsed/common";
import * as Path from "path";
import {MyController} from "./controllers/manual/MyController";

const rootDir = Path.resolve(__dirname);

@ServerSettings({
  rootDir, // optional. By default it's equal to process.cwd()
  mount: {
    "/rest": "${rootDir}/controllers/current/**/*.js",
    "/rest/v1": [
      "${rootDir}/controllers/v1/users/*.js",
      "${rootDir}/controllers/v1/groups/**/*.ts", // support ts entry
      "!${rootDir}/controllers/v1/groups/old/*.ts", // support ts entry
      MyController // support manual import
    ]
  }
})
export class Server extends ServerLoader {
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

or when you bootstrap your Server (e.g. index.ts):

import {$log, ServerLoader} from "@tsed/common";
import {Server} from "./Server";

async function bootstrap() {
  try {
    $log.debug("Start server...");
    const server = await ServerLoader.bootstrap(Server);

    await server.listen();
    $log.debug("Server initialized");
  } catch (er) {
    $log.error(er);
  }
}

bootstrap();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Ts.ED support ts-node. Ts extension will be replaced by a Js extension if ts-node isn't the runtime.

TIP

In addiction, it also possible to use node-config or dotenv to load your configuration from file:

import {$log, ServerLoader} from "@tsed/common";
import {Server} from "./Server";

process.env["NODE_CONFIG_DIR"] = __dirname + "/../config";
const config = require("config");

async function bootstrap() {
  try {
    $log.debug("Start server...");
    const server = await ServerLoader.bootstrap(Server, config /* or config.util.toObject() */);

    await server.listen();
    $log.debug("Server initialized");
  } catch (er) {
    $log.error(er);
  }
}

bootstrap();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

You should have this tree directories:

.
├── config
│   └── default.json (or .yaml)
├── src
│   ├── controllers
│   ├── services
│   ├── middlewares
│   ├── index.ts
│   └── Server.ts
└── package.json
1
2
3
4
5
6
7
8
9
10

With dotenv:

import {$log, ServerLoader} from "@tsed/common";
import {Server} from "./Server";

const config = require('dotenv').config({ path: '/full/custom/path/to/your/env/vars' });

async function bootstrap() {
  try {
    $log.debug("Start server...");
    const server = await ServerLoader.bootstrap(Server, config /* or config.util.toObject() */);

    await server.listen();
    $log.debug("Server initialized");
  } catch (er) {
    $log.error(er);
  }
}

bootstrap();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Options

  • rootDir <string>: The root directory where you build run project. By default, it's equal to process.cwd().
  • env <Env>: The environment profile. By default the environment profile is equals to NODE_ENV.
  • port <string | number>: Port number for the HTTP.Server.
  • httpsPort <string | number>: Port number for the HTTPs.Server.
  • httpsOptions <Https.ServerOptions)>:
    • key <string> | <string[]> | <Buffer> | <Object[]>: The private key of the server in PEM format. To support multiple keys using different algorithms an array can be provided either as a plain array of key strings or an array of objects in the format {pem: key, passphrase: passphrase}. This option is required for ciphers that make use of private keys.
    • passphrase <string> A string containing the passphrase for the private key or pfx.
    • cert <string> | <string[]> | <Buffer> | <Buffer[]>: A string, Buffer, array of strings, or array of Buffers containing the certificate key of the server in PEM format. (Required)
    • ca <string> | <string[]> | <Buffer> | <Buffer[]>: A string, Buffer, array of strings, or array of Buffers of trusted certificates in PEM format. If this is omitted several well known "root" CAs (like VeriSign) will be used. These are used to authorize connections.
  • uploadDir <string>: The temporary directory to upload the documents. See more on Upload file with Multer.
  • mount <IServerMountDirectories>: Mount all controllers under a directories to an endpoint.
  • componentsScan <string[]>: List of directories to scan Services, Middlewares or Converters.
  • exclude <string[]>: List of glob patterns. Exclude all files which matching with this list when ServerLoader scan all components with the mount or scanComponents options.
  • statics <IServerMountDirectories>: Object to mount all directories under to his endpoints. See more on Serve Static.
  • swagger <Object>: Object configure swagger. See more on Swagger.
  • routers <object>: Global configuration for the Express.Router. See express documentation.
  • validationModelStrict <boolean>: Use a strict validation when a model is used by the converter. When a property is unknown, it throw a BadRequest (see Converters). By default true.
  • logger <ILoggerSettings>: Logger configuration.
  • controllerScope <request|singleton>: Configure the default scope of the controllers. Default: singleton. See Scope.
  • acceptMimes <string[]>: Configure the mimes accepted by default by the server.
  • errors <IErrorsSettings>: Errors configuration (see Throw Http exceptions).

Versioning REST API

Ts.ED provide the possibility to mount multiple Rest path instead of the default path /rest. You have two methods to configure all global endpoints for each directories scanned by the ServerLoader.

import {ServerLoader, ServerSettings} from "@tsed/common";
import Path = require("path");
const rootDir = Path.resolve(__dirname);

@ServerSettings({
   rootDir,
   mount: {
     "/rest": "${rootDir}/controllers/current/**/*.js",
     "/rest/v1": [
        "${rootDir}/controllers/v1/users/*.js",
        "${rootDir}/controllers/v1/groups/*.js"
     ]
   }
})
export class Server extends ServerLoader {

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Note: mount attribute accept a list of glob for each endpoint. That lets you declare a resource versioning.

HTTP & HTTPs server

Change address

It's possible to change the HTTP and HTTPS server address as follows:

import {ServerLoader, ServerSettings} from "@tsed/common";

@ServerSettings({
   httpPort: "127.0.0.1:8081",
   httpsPort: "127.0.0.2:8082",
})
export class Server extends ServerLoader {}
1
2
3
4
5
6
7

Random port

Random port assignment can be enable with the value 0. The port assignment will be delegate to the OS.

import {ServerLoader, ServerSettings} from "@tsed/common";

@ServerSettings({
   httpPort: "127.0.0.1:0",
   httpsPort: "127.0.0.2:0",
})
export class Server extends ServerLoader {}
1
2
3
4
5
6
7

Or:

import {ServerLoader, ServerSettings} from "@tsed/common";

@ServerSettings({
   httpPort: 0,
   httpsPort: 0,
})
export class Server extends ServerLoader {}
1
2
3
4
5
6
7

Disable HTTP

import {ServerLoader, ServerSettings} from "@tsed/common";

@ServerSettings({
   httpPort: false
})
export class Server extends ServerLoader {}
1
2
3
4
5
6

Disable HTTPS

import {ServerLoader, ServerSettings} from "@tsed/common";

@ServerSettings({
   httpsPort: false,
})
export class Server extends ServerLoader {}
1
2
3
4
5
6

HTTPs configuration

You see the example projet HTTPs

Logger

Default logger

Default logger use by Ts.ED is ts-log-debug.

Configuration

Some options is provided:

  • logger.level: Change the default log level displayed in the terminal. Values: debug, info, warn or error. By default: info.
  • logger.logRequest: Log all incoming request. By default is true and print the configured logger.requestFields.
  • logger.requestFields: Fields displayed when a request is logged. Possible values: reqId, method, url, headers, body, query,params, duration.
  • logger.reqIdBuilder: A function called for each incoming request to create a request id.
  • logger.jsonIndentation: The number of space characters to use as white space in JSON output. Default is 2 (0 in production).
  • logger.disableRoutesSummary: Disable routes table displayed in the logger. By default debug is false.
  • logger.format: Specify log format. Example: %[%d{[yyyy-MM-dd hh:mm:ss,SSS}] %p%] %m. See ts-log-debug configuration.
  • logger.ignoreUrlPatterns (String or RegExp): List of pattern to ignore logged request according to the request.url.

It's recommended to disable logRequest in production. Logger have a cost on the performance.

Request logger

For each Express.Request, a logger will be attached and can be used like here:

request.log.info({customData: "test"}) // parameter is optional
request.log.debug({customData: "test"})
request.log.warn({customData: "test"})
request.log.error({customData: "test"})
request.log.trace({customData: "test"})
1
2
3
4
5

A call with once of this method will generate a log according to the logger.requestFields configuration:

[2017-09-01 11:12:46.994] [INFO ] [TSED] - {
  "status": 200,
  "reqId": 1,
  "method": "GET",
  "url": "/api-doc/swagger.json",
  "duration": 92,
  "headers": {
    "host": "0.0.0.0:8001",
    "connection": "keep-alive",
    "upgrade-insecure-requests": "1",
    "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36",
    "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
    "accept-encoding": "gzip, deflate",
    "accept-language": "fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4"
  },
  "body": {},
  "query": {},
  "customData": "test"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

You can configure this output from configuration:

import {ServerLoader, ServerSettings} from "@tsed/common";

@ServerSettings({
   logger: {
       requestFields: ["reqId", "method", "url", "headers", "body", "query","params", "duration"]
   }
})
export class Server extends ServerLoader {

}
1
2
3
4
5
6
7
8
9
10

or you can override the middleware with .

Example:

import {LogIncomingRequestMiddleware, OverrideProvider, Req} from "@tsed/common";

@OverrideProvider(LogIncomingRequestMiddleware)
export class CustomLogIncomingRequestMiddleware extends LogIncomingRequestMiddleware {

  public use(@Req() request: any) {

    // you can set a custom ID with another lib
    request.id = require("uuid").v4();

    return super.use(request); // required
  }

  protected requestToObject(request: any) {
    return {
      reqId: request.id,
      method: request.method,
      url: request.originalUrl || request.url,
      duration: new Date().getTime() - request.tsedReqStart.getTime(),
      headers: request.headers,
      body: request.body,
      query: request.query,
      params: request.params
    };
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

Shutdown logger

Shutdown return a Promise that will be resolved when ts-log-debug has closed all appenders and finished writing log events. Use this when your program exits to make sure all your logs are written to files, sockets are closed, etc.

import {$log} from "ts-log-debug";

$log
  .shutdown()
  .then(() => {
     console.log("Complete")
  }); 
1
2
3
4
5
6
7

Get configuration

The configuration can be reused throughout your application in different ways.

From service (DI)

import {Configuration, Service} from "@tsed/di";

@Service() // or Controller or Middleware
export class MyService {
  constructor(@Configuration() configuration: Configuration) {}
}
1
2
3
4
5
6

From decorators

Decorators and can be used in all classes including:

and accept an expression as parameters to inspect the configuration object and return the value.

import {Constant, Value} from "@tsed/di";
import {Env} from "@tsed/core";

export class MyClass {
  @Constant("env")
  env: Env;

  @Value("swagger.path")
  swaggerPath: string;

  $onInit() {
    console.log(this.env);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

WARNING

return an Object.freeze() value.

NOTE

The values for the decorated properties aren't available on constructor. Use $onInit() hook to use the value.