# Platform API

Ts.ED uses now the Platform API to create an application. Platform API gives an abstraction layer between your code written with Ts.ED and the Express.js (opens new window) code. It means that a large part of your code isn't coupled with Express.js itself and can be used with another Platform like Koa.js (opens new window).

There are some changes between ServerLoader API (v4/v5) and Platform API (v5.56.0+/v6), to get the original Express Application, Request or Response. This page will describe how you can get these instances with the new API.

# Platform classes

    # Create application

    The way to create a Ts.ED application, add middlewares, configure Express or Koa, all are impacted by the new Platform API.

    If you use ServerLoader, you'll probably know this example to create a Ts.ED application:

    import {ServerLoader, ServerSettings} from "@tsed/common";
    import {MyMiddleware} from "./MyMiddleware";
    import * as bodyParser from "body-parser";
    import * as compress from "compression";
    import * as cookieParser from "cookie-parser";
    import * as methodOverride from "method-override";
    
    export const rootDir = __dirname;
    
    @ServerSettings({
      rootDir,
      viewsDir: `${rootDir}/views`
    })
    export class Server extends ServerLoader {
      $beforeRoutesInit() {
        this
         .use(MyMiddleware)
         .use(cookieParser())
         .use(compress({}))
         .use(methodOverride())
         .use(bodyParser.json())
         .use(bodyParser.urlencoded({
           extended: true
         }));
       
        // configure express app
        this.set("views", this.settings.get('viewsDir'));
        this.engine("ejs", ejs);
      }
    }
    
    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
    27
    28
    29
    30

    With Platform API you have to inject PlatformApplication to register a middleware and set configuration to Express.Application:

    import {Configuration, PlatformApplication} from "@tsed/common"; 
    import {Inject, Constant} from "@tsed/di";
    import {MyMiddleware} from "./MyMiddleware";
    import * as bodyParser from "body-parser";
    import * as compress from "compression";
    import * as cookieParser from "cookie-parser";
    import * as methodOverride from "method-override";
    
    export const rootDir = __dirname;
    
    @Configuration({
      rootDir,
      views: {
        root: `${rootDir}/views`,
        viewEngine: 'ejs'
      }
    })
    export class Server {
      @Constant("viewsDir")
      viewsDir: string;
    
      @Inject()
      app: PlatformApplication<Express.Application>;
    
      $beforeRoutesInit() {
        this.app
         .use(MyMiddleware)
         .use(cookieParser())
         .use(compress({}))
         .use(methodOverride())
         .use(bodyParser.json())
         .use(bodyParser.urlencoded({
           extended: true
         }));
      }
    }
    
    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36

    TIP

    With Platform API, the Server class is considered as a Provider . It means that you can use decorators like Constant and Inject to get any configuration, provider or service from the DI registry.

    # Inject service in the Server

    With ServerLoader, injecting a provider can be done as follows:

    import {ServerLoader, ServerSettings} from "@tsed/common";
    import {MyService} from "./services/MyService";
    
    @ServerLoader({
    })
    export class Server extends ServerLoader {
      $beforeRoutesInit() {
        const myService = this.injector.get<MyService>(MyService);
    
        myService.getSomething();
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    Now with Platform API, the Server class is considered as a Provider . It means that you can use decorators like Constant and Inject to get any configuration, provider or service from the DI registry.

    import {Configuration} from "@tsed/common"; 
    import {Inject} from "@tsed/di";
    import {MyService} from "./services/MyService";
    
    @Configuration({})
    export class Server {
      @Inject()
      myService: MyService;
    
      $beforeRoutesInit() {
        this.myService.getSomething();
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13

    # Bootstrap application

    In v5, boostrap a Server can be done with the ServerLoader.boostrap method:

    import {$log, ServerLoader} from "@tsed/common";
    import {Server} from "./server";
    
    async function bootstrap() {
      try {
        $log.debug("Start server...");
        const platform = await ServerLoader.bootstrap(Server, {
          // extra settings
        });
    
        await platform.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

    Now with Platform API, you have to install @tsed/platform-express (or @tsed/platform-koa) and change the code by the following example:

    import {$log} from "@tsed/common";
    import {PlatformExpress} from "@tsed/platform-express";
    import {Server} from "./server";
    
    async function bootstrap() {
      try {
        $log.debug("Start server...");
        const platform = await PlatformExpress.bootstrap(Server, {
          // extra settings
        });
    
        await platform.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

    # Get Application

    Before with v5, to get Express.Application, you had to use ExpressApplication decorator:

    import {Injectable} from "@tsed/di";
    import {ExpressApplication} from "@tsed/common";
    
    @Injectable()
    class MyService {
      constructor(@ExpressApplication private app: ExpressApplication) {
      }
     
      getExpressApp(){
         return this.app;
      }
    } 
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    With Platform API, you have to inject PlatformApplication and use the app.raw or app.getApp() to get the Express.Application:

    import {Injectable, Inject} from "@tsed/di";
    import {PlatformApplication} from "@tsed/common";
    import {MyMiddleware} from "../middlewares/MyMiddleware";
    
    @Injectable()
    class MyService {
      @Inject()
      app: PlatformApplication<Express.Application>;
     
      getExpressApp(){
         return this.app.raw; // GET Express raw Application. E.g.: const app = express()
      }
      
      $onInit() {
        // With Platform API, it is also possible to add middlewares with a service, module, etc...
        this.app.use(MyMiddleware); 
      }
    } 
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    # Request and Response

    There is no big change over Response and Request, you can always get Request and Response by using decorators. With the Platform API, you are also able to use Context decorator to deal with the PlatformRequest or PlatformResponse high level API.

    See Request context page to get more details.

    # Statics files

    Since v5.65.0, Platform API manages also the statics files. The Unable to find something: symbolName === "ServeStaticService" is now deprecated in favor of PlatformApplication.statics() method.

    Before:

    import {Injectable} from "@tsed/di";
    import {ServeStaticService} from "@tsed/common";
    
    @Injectable()
    class MyService {
      constructor(private service: ServeStaticService) {
      }
     
      $onReady () {
        this.service.statics({"/endpoint":  __dirname + "/publics"});
      }
    } 
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    After:

    import {Injectable} from "@tsed/di";
    import {PlatformApplication} from "@tsed/common"; 
    
    @Injectable()
    class MyService {
      constructor(private app: PlatformApplication) {
      }
     
      $onReady () {
        this.app.statics("/endpoint",   {root: __dirname + "/publics"});
      }
    } 
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    # Catch exceptions

    The new Platform API introduces a new way to catch an exception with the Catch decorator, and to let you control the exact flow of control and the response's content sent back to the client.

    See Exception filter page to get more details.

    Last Updated: 12/4/2020, 12:31:38 PM

    Other topics