docker-composeを使ってNode.jsアプリのインテグレーションテストを行う #1

# 本記事の目的
今回の記事はシリーズになります。
Node.jsでのREST APIサーバー開発から始めて、最終目標はdocker-composeを用いてREST APIサーバーとDBからなるWebアプリの自動インテグレーションテストを作成する事です。現在、Docker/Kubernetesを用いたマイクロサービス作成が流行しており、一般的なWebアプリではバックエンドサーバのコンテナがHTTP通信を受け取り、リソースの管理はDBコンテナを用いて行うことが多いと思います。このようなコンテナ群を結合して機能を保証するために、インテグレーションテストを自動で行うことが求められます。docker-composeを用いることで、ローカル環境でインテグレーションテストを構築する事ができます。今回のシリーズではあつかいませんが、本番環境を想定してCI/CDパイプラインでクラスタ上でのインテグレーションテストを行うための足掛かりになると思います。

今回の記事で、Node.jsの開発環境を整えます。
[次回の記事](https://qiita.com/youk-h/items/3827694d084e20687f90)で、Node.jsを用いてPostgresへSQLを投げる実装を行います。

ソースコードは以下で、記事公開時に更新していきます。
https://github.com/youk-h/Integration-test

# 対象読者
・Node.jsを用いた実装に興味がある方
・dockerの利用例の一例を知りたい方

## REST APIサーバを作成準備
今回は、REST API サーバを作るためにNode.jsと[Express.js](https://expressjs.com/)をインストールします。

### Node.js インストール
おすすめの方法は、Node.jsのバージョン管理ツールである nvm を用いたインストールです。

windowsを使っている方は、[ここをクリック](https://github.com/coreybutler/nvm-windows/releases/download/1.1.7/nvm-setup.zip)するとzipファイルのインストールが始まります。
解凍後、環境変数のNVM_HOMEに実行ファイルまでのパスを設定してください。

Mac/Linuxを使っている方は[公式ページの](https://github.com/nvm-sh/nvm) Install & Update script の項目を参考にインストールしてください。

インストールが終われば、ターミナルから以下のコマンドを実行してNode.js の v10.16.0（記事投稿時ののLTS）をインストールします。
`nvm install 10.16.0`
インストールしたNode.js 10.16.0を使うために以下のコマンドを実行してください。
`nvm use 10.16.0`

以上で、Node.jsでのプログラミング環境が整いました。

### 開発環境のセットアップ
Node.jsアプリのセットアップには npm というNode.jsのパッケージマネージャを使います。
実は、nvm で Node.jsをインストールしたときに、この npm もインストールされています。
以下のコマンドでバージョンを確認できます(v6.9.0 が入っていると思います)。
`npm -v` 

アプリ用のディレクトリを作って以下のコマンドを実行してすべての質問にEnterを押してください。
`npm init`
そうするとPackage.jsonというファイルができます。
これが、Node.jsのパッケージ管理ファイルで、アプリの依存モジュールはすべてここで管理します。

### Express.js のインストール
Express.jsをインストールしてREST APIサーバ作成の準備を行います。Express.jsはREST APIのルーティングを行うためのミドルウェアを提供します。このミドルウェアの良い点は、単機能な関数群を連結させて処理を実装できることです。以下のコマンドでインストールできます。
`npm install --save express`
ここで、--saveをつけたのは、先ほど作ったpackage.jsonにexpressを登録するためです。上のコマンドを実行後、package.jsonのdependeciesにexpressがあることが分かります。このdependenciesにあるモジュールは`npm install`で自動的にインストールできるようになります。

### Express.js を使ってコーディングしてみる
今回は、Typescriptを用いて実装を行うので以下のコマンドで、Typescriptパッケージ と tsファイルを直接実行するためのts-nodeをインストールします。
`npm install -D typescript ts-node`

また、express.js は Javascript のモジュールですが、@types/express をインストールすることで express の型が分かり、インテリセンスを効かせることができるので以下のコマンドでインストールします。
`npm install -D @types/express`

ここで、-Dというオプションを付けたのは、デバッグ環境でだけ使うモジュールを package.json に登録するために付けています。実行後、package.json を見ると devDependencies という項目が作成され、この3つのモジュールが入っていることが分かります。

以下に、expressを使ってポート3000でのリクエストに対して Hello World を返す Web アプリを router.ts という名前で作成します。express の文法を詳しく知りたい人は[このページ](https://expressjs.com/en/4x/api.html)を参考にしてください。

``` typescript
// router.ts
// express の exportされている全ての関数などを express という名前を付けて improt している 
import * as express from "express";

// このアプリの実体を作成します
const app = express();
// 公開ポートを指定します
const port = 3000;

// http get メソッドのパス / に対して Hello World を返します
app.get("/", (req, res) => res.send("Hello World"));

// アプリをポート3000で公開します
app.listen(port, () => console.log("listen to" + port));
```

このTypescriptアプリを以下のコマンドで実行して、ポート3000で公開します。
`ts-node router.ts`
立ち上げた後に、http://localhost:3000 にアクセスすると Hello World が表示されます。

### HTTPリクエストを受け付けるサーバを作成する
ここからは、REST APIを受け付けるためのインターフェースを作成していきます。rest-api.ts というファイルにREST APIの処理を行うためのハンドラーを作成します。

```typescript
/* rest-api.ts
* 以下ではCRUDに対応したハンドラー用の関数を作成しています。
* 実装は次回の記事で行っていきます。現段階では、それぞれ単に get, post, put, deleteというメッセージ を返すだけです
* ここで作っている関数はすべてexportで公開しているので、外部のファイルからすべてimportできます。
*/

// expressアプリで使うRequestとResponseをimportしています
import { Request, Response } from "express";

export function getHandler(req: Request, res: Response) {
  return res.send("get cars").end();
};

export function postHandler(req: Request, res: Response) {
  return res.send("post cars").end();
};

export function putHandler(req: Request, res: Response) {
  return res.send("put cars").end();
};

export function deleteHandler(req: Request, res: Response) {
  return res.send("delete cars").end();
};

```

```typescript
// router.ts
import * as express from "express";
// 上で作ったrest-api.tsのすべてのハンドラーをimportしています
import * as restApi from "./rest-api";

const app = express();
const port = 3000;

// 先ほどは、appのgetメソッドを使いましたが、ここではREST API用のルーターを作成しています
const restApiRouter = express.Router();

// このアプリに来たすべてのHTTPリクエストをREST API のルーターである restApiRouter へ誘導しています。
app.all("*", restApiRouter);

// restApiRouter に渡ってきたリクエストを CRUD 処理を行うための API へルーティングします。
// 該当するメソッドが無い、もしくはパスが/carsでなければ、expressがステータスコード404でレスポンスを返します。
restApiRouter.get("/cars", restApi.getHandler);
restApiRouter.post("/cars", restApi.postHandler);
restApiRouter.put("/cars", restApi.putHandler);
restApiRouter.delete("/cars", restApi.deleteHandler);

app.listen(port, () => console.log(`listen to ${port}`));
```

アプリを実行するのは先ほどと同様に以下のコマンドを実行します。
`ts-node router.ts`
立ち上げた後に、http://localhost:3000 にアクセスすると get が表示されます。
post, put, deleteに関しては、[Postman](https://www.getpostman.com/downloads/)から実行して確かめられます。

# まとめ
今回は、Node.js を使ってREST API 用のアプリを構成しました。
次回は、Postgresコンテナを立ち上げて、Node.jsからCRUDを行う内容を実装する予定です。