Skip to content

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 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.

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

Abstraction

Loading in progress...

Express.js

Loading in progress...

Koa.js

Loading in progress...

Serverless

Loading in progress...

Create application

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

Here is the common way to configure a server using the Platform API:

typescript
import {Configuration, PlatformApplication} from "@tsed/common";
import {Inject, Constant} from "@tsed/di";
import {MyMiddleware} from "./MyMiddleware";

@Configuration({
  views: {
    root: `${process.cwd()}/views`,
    viewEngine: "ejs"
  },
  middlewares: [MyMiddleware, "cookie-parser", "compression", "method-override"]
})
export class Server {
  @Constant("viewsDir")
  viewsDir: string;

  $beforeRoutesInit() {
    console.log(this.viewsDir);
  }
}

We can see that the middlewares and views are configured through the @Configuration decorator.

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. Also, there decorators can be used in any Service or Injectable class.

By this way, we can decouple the configuration from the code and make it more testable and more adaptable to different frameworks (Express, Koa, etc...).

Bootstrap application

Ts.ED need a Platform Adapter to work. It means that you have to install @tsed/platform-express (or @tsed/platform-koa) and import the adapter to the index.ts or server.ts:

typescript
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();
typescript
import {$log} from "@tsed/common";
import {PlatformKoa} from "@tsed/platform-koa";
import {Server} from "./server";

async function bootstrap() {
  try {
    $log.debug("Start server...");
    const platform = await PlatformKoa.bootstrap(Server, {
      // extra settings
    });

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

bootstrap();

Get Application

To get the framework application instance (Express.js, Koa.js), you have to inject PlatformApplication and use app.getApp() to get the Express.Application:

typescript
import {Injectable, Inject} from "@tsed/di";
import {PlatformApplication} from "@tsed/common";
import {MyMiddleware} from "../middlewares/MyMiddleware";

@Injectable()
class MyService {
  @Inject()
  protected app: PlatformApplication<Express.Application>;

  getExpressApp() {
    return this.app.getApp(); // GET Express raw Application. E.g.: const app = express()
  }

  $onInit() {
    // With Platform API, it is also possible to adding middlewares with a service, module, etc...
    this.app.use(MyMiddleware);
  }
}
typescript
import {Injectable, Inject} from "@tsed/di";
import {PlatformApplication} from "@tsed/common";
import {MyMiddleware} from "../middlewares/MyMiddleware";

@Injectable()
class MyService {
  @Inject()
  protected app: PlatformApplication<Koa>;

  getExpressApp() {
    return this.app.getApp(); // GET Koa raw Application. E.g.: const app = new Koa()
  }

  $onInit() {
    // With Platform API, it is also possible to adding middlewares with a service, module, etc...
    this.app.use(MyMiddleware);
  }
}

Request and Response

There are no significant changes to 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

To serve static files, you can use the @Configuration decorator:

typescript
@Configuration({
  statics: {
    "/before": [
      {
        root: `${process.cwd()}/public`,
        hook: "$beforeRoutesInit"
        // ... statics options
      }
    ],
    "/after": [
      {
        root: `${process.cwd()}/public`,
        hook: "$afterRoutesInit"
        // ... statics options
      }
    ]
  }
})

Or use the app.statics() method:

typescript
import {Injectable} from "@tsed/di";
import {PlatformApplication} from "@tsed/common";
import {join} from "path";

@Injectable()
class MyService {
  constructor(private app: PlatformApplication) {}

  $onReady() {
    this.app.statics("/endpoint", {root: join(process.cwd(), "../publics")});
  }
}

Catch exceptions

Platform API provide a 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.

Released under the MIT License.