🐴

ExpressoTS 入門

2023/08/02に公開

はじめに

今回の記事では、今年にリリースされたTypeScriptフレームワークであるExpressoTSの概要と、それを使った簡単なWebサーバを構築する手順を解説する。

対象とする読者

  • タイトルを読んで気になったひと
  • 実務でTypeScriptを触っているひと
  • TypeScriptでWebサーバを構築したいひと

ExpressoTSとは

ExpressoTSとは、NestJSと同様にTypeScriptで開発されたバックエンドフレームワークである。公式サイトのIntroductionには、以下のように説明されている。

ExpressoTS is a TypeScript lightweight framework for building scalable, readable and maintainable server-side applications. The framework provides a level of abstraction on top of common HTTP server framework Expressjs exposing their API's directly to the developer. This provides freedom and brings to the developer a tool that is well known and easy to use.

和訳

ExpressoTSは、スケーラブルで読みやすく保守性の高いサーバサイドアプリケーションを構築するためのTypeScript軽量フレームワークである。このフレームワークは、一般的なHTTPサーバフレームワークであるExpressjsの上に抽象化レベルを提供し、そのAPIを開発者に直接公開する。これは自由を提供し、開発者によく知られた使いやすいツールをもたらす。

上述の英文を簡潔にまとめると、ExpressoTSはExpressjsをもとに開発されたバックエンドのWebフレームワークである。

ExpressoTSの特徴

公式サイトによれば、ExpressoTSの特徴には次の3つの特徴がある。

  1. シンプルな構造
  2. 柔軟性と拡張性が高い
  3. 強力な依存性注入システム

ExpressoTSの特徴を語る上で欠かせないのは3.の特徴だ。

依存性注入とは?

依存性注入(Dependency Injection)とはコードの柔軟性を高めるためのプログラミング手法の一つだ。これは、あるオブジェクトや関数が、依存する他のオブジェクトや関数を受け取るデザインパターンを意味する。

たとえば、あるクラスがデータベース接続に依存しているケースを仮定しよう。依存性注入を使用しない場合、このクラスは特定のデータベース接続に固定され、他のデータベースに対応するためにはクラス自体を書き換える必要がある。ここで、依存性注入を使えばこのクラスにデータベース接続を「注入」することができ、どのデータベースにも対応できるようになる。

依存性注入とは、あるコードが他のコードに依存している場合、それを直接結びつけるのではなく依存性注入を用いて後から「注入」できるのだ。

ExpressoTSにおける依存性注入

ExpressoTSは以下の4種類のコンポーネントで依存性注入を実装する。

表1 ExpressoTSの依存性注入を支える4種類のコンポーネント

コンポーネント 説明
Container ExpressTSアプリケーションにおける依存性注入のコンテナ。依存性注入システムの心臓部。リクエストごとに新しいクラスのインスタンスを作成する
Module 関連するコントローラとその依存関係をグループ化するために使われる。独自のスコープ定義を持つ
Controller クライアントとサーバ間の主要なインターフェイス。入ってくるリクエストを処理する役割を持つ。原則、アプリケーションの機能を持つモジュールにグループ化される。常にモジュールと関連付けられる
Classes ExpressTSのエコシステム内に存在するクラス。

簡単なWebサーバを構築する手順

本章からは、ExpressoTSで簡単なWebサーバを構築する方法を解説する。

(1) インストール

以下のコマンドでExpressoTS CLIをインストールする。

npm i -g @expressots/cli

(2) プロジェクトを新しくつくる

以下のコマンドを入力する。

npx expressots new sample-expresso

(3) サーバを立ち上げる

以下のコマンドでサーバを立ち上げる。

cd sample-expresso
npm run dev

ディレクトリの説明

手順のセクションの(2)で紹介したコマンドを入力すると、以下のようなディレクトリが作られる。

sample-expresso/
├── src/
│   ├── app.container.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.usecase.ts
│   ├── main.ts
├── test/
│   ├── app.usecase.spec.ts

表2 ExpressoTSアプリケーションの初期ディレクトリ内にあるファイルとその説明

ファイル名 説明
app.container.ts ExpressoTSアプリケーションのすべてのモジュールを、まとまりのあるユニット(コンテナ)に編成する役割を持つ
app.controller.ts ExpressoTSのコントローラの心臓部
app.module.ts ExpressoTSのルートモジュール
app.usecase.ts ユーザや他のシステム、ソフトウェアアプリケーション間の相互作用をモデル化するファイル
main.ts ExpressoTSのエントリポイント
app.usecase.spec.ts app.usecase.tsの単体テストを行うファイル。今回の記事では解説しない

app.container.ts

このファイルはExpressoTSアプリケーションにおけるコンテナ(Container)を管理・実装する。依存関係を管理し、他のオブジェクトに依存するオブジェクトを作成するっための中核となるコードを提供する。

ExpressoTSアプリケーションのコンテナを実装する上で、InversifyJSが採用されている。これを使うことで、TypeScriptの最大の特徴である「型」を最大限に活用したコンテナを実装できるのだ。

// (1) 必要なパッケージをインポート
import { AppContainer } from "@expressots/core";
import { AppModule } from "./app.module";

// (2) コンテナのインスタンスを作成する
const appContainer = new AppContainer();

// (3) コンテナ内で作動させるモジュールを追加する
const container = appContainer.create([
    // Add your modules here
    AppModule,
]);

// (4) 変数containerをエクスポートする
export { container };

app.controller.ts

このファイルはExpressoTSアプリケーションのコントローラ(Controller)を担当する。言いかえれば、ExpressoTSアプリケーションのクライアントとサーバ間(ExpressoTSではusecaseと言われる)の主要なインターフェイスとして機能する。

// (1) 必要なパッケージをインポート
import { BaseController } from "@expressots/core";
import { controller, httpGet, response } from "inversify-express-utils";
import { Response } from "express";
import { AppUseCase } from "./app.usecase";

// (2) ルートパスを定義し、BaseControllerを継承したAppControllerクラスを作成する
@controller("/")
class AppController extends BaseController {
    constructor(private appUseCase: AppUseCase) {
        super("app-controller");
    }

    // ルートパスへのGETリクエストを処理する
    @httpGet("/")
    execute(@response() res: Response) {
        return res.send(this.appUseCase.execute());
    }
}

// (3) AppControllerクラスをエクスポート
export { AppController };

app.module.ts

このファイルは、ExpressoTSにおけるコントローラとその依存関係をグループ化するモジュール(Module)を管理するファイルだ。

// (1) 必要なパッケージをインポート
import { CreateModule } from "@expressots/core";
import { AppController } from "./app.controller";

// (2) AppModuleを以下のように書く
const AppModule = CreateModule([AppController]);

// (3) AppModuleをエクスポート
export { AppModule };

app.usecase.ts

このファイルは、ユーザ、他のシステムやアプリケーション間の相互作用をモデル化する方法を提供する。ExpressoTSにおけるusecaseは、アプリケーションのビジネスロジックを意味し、コントローラとリクエストの実行を明確に分離する。

アプリケーションのビジネスロジックを簡潔に説明すると、アプリケーションの主要な機能をコントロールし、データの作成、表示や変更等を管理する。

// (1) InversifyJSのライブラリ(依存性注入に特化)をインポート
import { provide } from "inversify-binding-decorators";

// (2) @provideデコレータ付きのAppUseCaseクラスを定義。ここにビジネスロジックを実装
@provide(AppUseCase)
class AppUseCase {
    // execute関数を作成。"Hello Expresso TS!"という文字列を返す
    execute() {
        return "Hello Expresso TS!";
    }
}

// (3) AppUseCaseクラスをエクスポート
export { AppUseCase };

そして、このファイルで書いたAppUseCaseクラスの処理が、app.controller.tsにて以下のコードで処理される。

@controller("/")
class AppController extends BaseController {
    // AppUseCaseクラスを型定義ライクでここで呼び出す
    constructor(private appUseCase: AppUseCase) {
        super("app-controller");
    }

    // こちらの部分に注目
    @httpGet("/")
    execute(@response() res: Response) {
        return res.send(this.appUseCase.execute()); // execute関数をthisを用いて実行
    }
}

main.ts

main.tsは、ExpressoTSアプリケーションのエントリポイントを記述するファイルだ。main.tsは以下のように記述される。

// (1) デコレータとメタデータのAPIを利用するためのライブラリをインポート
import "reflect-metadata";

// (2) 必要なパッケージをインポート
import { AppInstance, ServerEnvironment } from "@expressots/core";
import { container } from "./app.container";

// (3) サーバを立ち上げるbootstrap関数(非同期関数)を作る
async function bootstrap() {
    AppInstance.create(container);
    // 3000番のポートでサーバを立ち上げる
    AppInstance.listen(3000, ServerEnvironment.Development);
}

// (4) bootstrap関数の実行
bootstrap();

余談:ExpressoTSとNestJSのディレクトリ比較

余談になるが、ExpressoTSアプリケーションの初期のディレクトリはNestJSのものと非常に類似している。特にsrcフォルダとそのファイルの名前が非常に似ている。参考までに、NestJSの場合は以下のようになる。

▼NestJSの初期のディレクトリ

project-name
├── node_modules/
├── src/
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   └── main.ts
├── test/
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── .gitignore
├── nest-cli.json
├── package.json
├── README.md
├── tsconfig.build.json
└── tsconfig.json

srcフォルダに着目すると、ディレクトリ構造とそのファイル名が類似していることがわかるだろう。

▼NestJSのsrcフォルダ

project-name/
├── src/
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   └── main.ts

▼ExpressoTSのsrcフォルダ

project-name/
├── src/
│   ├── app.container.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.usecase.ts
│   ├── main.ts

おわりに

今回の記事ではTypeScriptのバックエンドフレームワークであるExpressoTSの概要、簡単なWebサーバを構築する手順やディレクトリ構造を説明した。ExpressoTSはシンプルさと強固な依存性注入システムを最大の特徴に持つフレームワークだ。同じくTypeScriptでバックエンドを開発できるフレームワークであるNestJSの良い対抗馬になりそうである。

参考サイト

https://expresso-ts.com/

https://doc.expresso-ts.com/docs/overview/intro

GitHubで編集を提案

Discussion