Express(Node.js)でTypeScriptを利用した開発環境構築 ~REST APIのひな形を作成する~

2020年12月13日TypeScript,express(node.js),Development

フロント側ではReact、Vue、Angularなどは静的型付け言語であるTypeScriptでコーディングされることが一般的になってきました。

今回は、Node.jsのフレームワークであるExpressについてもJavaScriptではなくTypeScriptでコーディングするために開発環境の構築方法をまとめました。

この記事で出来るようになること

  • ExpressとTypeScriptがインストールできる
  • 開発を効率化するためにコーディングがリアルタイムで反映されるように設定できる
  • ビルドとビルド済みJSファイルの実行方法がわかる
  • REST APIの作り方の雰囲気がわかる

Express+TypeScriptの開発環境構築手順

Node.jsのインストール

各環境(Windows、Mac、Dockerコンテナ内など)に合わせてNode.jsをインストールして下さい。

ここでは、Node.jsのバージョンは14.15.1をインストールした状態で進めていきます。

$ node --version
v14.15.1

アプリケーションのディレクトリ構成

最終的なディレクトリ構成です。

 app
   ├─dist         ・・・ [自動作成] JavaScriptに変換されたファイルの出力先
   ├─node_modules ・・・ [自動作成] npmでインストールされる各種モジュール
   └─src          ・・・ [手動作成] package.json、index.tsなど
       └─route    ・・・ [手動作成] 
           └─v1   ・・・ [手動作成] REST APIの実態

npm initでpackage.json作成

$ mkdir app
$ cd app
$ npm init

npm initを実行すると対話形式でpackage.jsonを作成します。

特にデフォルトのままでEnterで問題なしです。

Express+TypeScript、開発環境やビルドに必要なパッケージのインストール

以下のパッケージをインストールします。

$ npm install express
$ npm install -D typescript
$ npm install -D @types/node
$ npm install -D @types/express
$ npm install -D ts-node
$ npm install -D ts-node-dev
$ npm install -D rimraf
$ npm install -D npm-run-all
  • ts-node-dev ・・・ プログラムの修正がリアルタイムで反映するため
  • rimraf ・・・ ビルド(TypeScriptからJavaScriptへの変換)先のディレクトリをクリアするため
  • npm-run-all ・・・ npmスクリプトを複数実行するため

package.jsonにコマンドなどの設定を行う

package.jsonのmainおよびscriptsについて以下のように設定する

   "main": "dist/index.js",
   "scripts": {
     "dev": "ts-node-dev --respawn src/index.ts",
     "clean": "rimraf dist",
     "tsc": "tsc",
     "build": "npm-run-all clean tsc",
     "start": "node ."
   },

TypeScriptの設定をする(tsconfig.json)

以下のコマンドを実行しTypeScriptの初期設定を行います。

$ npx tsc --init

作成されたtsconfig.jsonを自分好みにカスタマイズします。

ここでは、以下のように設定した前提で進めます。

{
  "compilerOptions": {
    "target": "ES5",
    "module": "commonjs",
    "sourceMap": true,
    "outDir": "./dist",
    "strict": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"]
}

srcディレクトリは以下を対象として、./distへビルド済みファイル(JavaScript)を出力する設定です。

ここまでで、環境構築は完了です。

package.jsonの各コマンドの使い方

[開発時]:npm run devで実行する

開発時する際は以下のコマンドで実行することで、プログラムの修正がリアルタイムで反映されるようになります。

これで、プログラムの修正の都度、「TypeScriptからJavaScriptへの変換」や「サーバの実行」をやり直す必要がなくなります。

$ npm run dev

> app@1.0.0 dev /workspace/app
> ts-node-dev --respawn src/index.ts

[INFO] 06:11:38 ts-node-dev ver. 1.1.1 (using ts-node ver. 9.1.1, typescript ver. 4.1.3)
Express WebApi listening on port 3000

Ctrl+Cでサーバ実行を停止できます。

[デプロイ用ビルド]:npm run buildでビルドする

デプロイ用にTypeScriptからJavaScriptへビルドする場合に以下のコマンドを実行します。

$ npm run build

> app@1.0.0 build /workspace/app
> npm-run-all clean tsc


> app@1.0.0 clean /workspace/app
> rimraf dist


> app@1.0.0 tsc /workspace/app
> tsc

/app/distディレクトリにJavaScriptに変換されたファイルが出力されています。

$ ls ./dist
index.js  index.js.map  routes

[デプロイ後の実行]:npm run startで実行する

/app/distのJavaScriptをnodeで実行します。

$ npm run start

> app@1.0.0 start /workspace/app
> node .

Express WebApi listening on port 3000

作成したテンプレートで簡単なREST APIを開発してみる

簡単にGET、POST、ルーティング処理だけを実装したサンプルです。

/app/src/index.ts

import express from 'express';
import router from './routes/v1/index';

const app = express();

// JSONオブジェクトの受信設定
app.use(express.json())
// 配列側のオブジェクトの受信設定
app.use(express.urlencoded({ extended: true }));

// ルーティング
app.use('/v1', router);

// 3000ポートで受信
const port = process.env.PORT || 3000;

// APIサーバ起動
app.listen(port);
console.log('Express WebApi listening on port ' + port);

/app/src/routes/v1/index.ts

import express from 'express';
import usersRouter from './users';

const router = express.Router();

// v1以下のルーティング
router.use('/users', usersRouter);

export default router;

/app/src/routes/v1/users.ts

import express from 'express';

const router = express.Router();

// GETリクエスト
router.get('/', (req: express.Request, res: express.Response) => {
  try {
    res.status(200).json({ userId: "U001", userName: "Yamada Taro" });
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
});

// POSTリクエスト
router.post('/', (req: express.Request, res: express.Response) => {
  try {
    res.status(200).json({ message: "登録しました" });
  } catch (error) {
    res.status(400).json({ message: error.message });
  }
});

export default router;

作成したREST APIを実行してみる

ここでは、開発モード(npm run dev)コマンドで実行してみます。

$ npm run dev

> app@1.0.0 dev /workspace/app
> ts-node-dev --respawn src/index.ts

[INFO] 07:58:28 ts-node-dev ver. 1.1.1 (using ts-node ver. 9.1.1, typescript ver. 4.1.3)
Express WebApi listening on port 3000

curlコマンドでアクセスすると結果を取得できました。

$ curl http://localhost:3000/v1/users
{"userId":"U001","userName":"Yamada Taro"}