Angular5 で俺式 KOAN スタック Webアプリ構築（3）

# バックエンド初期設定
- Angular5で「俺式KOANスタック」でWebアプリ構築するための個人的な備忘録記事。
- 概要については「[こちら](https://qiita.com/tomy0610/items/feaf4ced2ccb66373c15)」を参照。
- 事前に「[フロントエンド初期設定](https://qiita.com/tomy0610/items/c51ee4c73bfa238d3473)」が完了していることが前提。

## ライブラリの追加
※ 以下の作業は全て、package.json が存在する場所(プロジェクトフォルダ直下)までカレントディレクトリを移動してから行うこと

* ~~@angular/platform-server インストール~~ （インストール不要）

```bash
npm install --save @angular/platform-server
```

* Node.js のアプリをdaemon化する foever をインストール

```bash
npm install --save forever
```

>  `--save` オプションを指定すると `package.json` の `dependencies` に書き込まれる

* TypeScript インストール（angular-cli で自動生成時にインストール済みの場合はスキップ）

```bash
npm install --save-dev typescript ts-node
```

> `ts-node`：NodeJSの環境でTypeScriptを直接実行できるようにするツール
> `--save-dev` オプションを指定すると、`package.json` の `devDependencies` に書き込まれる。

* Koa V2 のインストール

```bash
npm install --save koa@2 koa-static koa-router koa-bodyparser
```

> `koa@2`：Koa v2 コアライブラリ
> `koa-static`：静的ファイル公開ライブラリ。指定したディレクトリにHTTPのパスを紐づける
> `koa-router`：ルーティング用ライブラリ。Koaのミドルウェアを束ねる用途で利用
> `koa-bodyparser`：リクエストデータを処理するための body-parser

* 型定義ファイルのインストール

```bash
npm install --save @types/koa-static @types/koa-router @types/koa-bodyparser http2
```

> `http2`：Koa v2 の型定義ファイルのインポートで使用するライブラリ。型定義がなければ不要のもの

## フォルダ および ファイル を追加
* ルートディレクトリ直下に `server` フォルダを作成し、新規に空のファイル `server.ts`, `tsconfig.json` を作成して以下のような構成にする

```
作成したプロジェクト名
　　　└─ server
         ├─ server.ts
         └─ tsconfig.json
```

## server.ts を仮設定
* `server/server.ts` を動作確認用に以下の通りに仮設定する

```typescript:server/server.ts
console.log('\n===== Hello, World! in server.ts =====');
```

## サーバ側の tsconfig ファイルを記述
`server/tsconfig.json` を以下の通りにする

```json:package:server/tsconfig.json
{
  "extends": "../tsconfig"
}

```

## 起動およびビルドコマンド修正
* `package.json` の `scripts` を以下の通りに修正する

```json:package.json
  "scripts": {
    "ng": "ng",
    "start": "npm run build && ts-node server/server.ts",
    "forever": "npm run build && forever start dist/server/server.js",
    "stop": "forever stop dist/server/server.js",
    "clean": "rm -rf dist",
    "build": "npm run clean && npm run build:client && npm run build:server",
    "build:client": "ng build --prod",
    "build:server": "tsc --project server --outDir dist",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
```

> 起動コマンドを `ng serve` から変更する

> forever の起動および停止を追加

> ビルド前のディレクトリを削除してからビルドを行うように修正

## 動作確認（仮設定）
* `npm run start` でサーバ（server.ts）を起動し、コンソール上に「`=== Hello, Koa!! ===`」と表示されたら成功。 `Ctrl + C` でサーバ停止。
* ルートディレクトリ直下の dist フォルダを削除してから `npm run build` でビルド実行し、ビルド完了後に dist フォルダ内に「client」「server 」フォルダが生成されていたら成功。
* `npm run forever` で daemon 化された状態で起動することが出来、かつ、起動後に `npm run stop` でサーバ停止する事ができたら成功。

## フォルダ および ファイル を追加
* ルートディレクトリ直下の `server` フォルダに、`app`, `controller`フォルダおよび、空のファイル `sample.controller.ts`, `middleware.router.ts`, `tsconfig.json` を作成して以下のような構成にする

```
server
 ├─ app
 │   └─ controller
 │       └─ sample.controller.ts
 │
 ├─ middleware.router.ts
 ├─ server.ts
 └─ tsconfig.json
```

## SampleController を記述
`server/app/controller/sample.controller.ts` を以下の通りにする

```typescript:server/app/controller/sample.controller.ts
/** サンプル コントローラ */
class SampleContoroller {
    public async test(request: any): Promise<any> {

        console.log('============ SampleContoroller # test ===========');
        console.log(request);

        return await {
            status: true,
            statusCode: 200,
            result: 1
        };
    }
}
export = SampleContoroller;

```

## MiddlewareRouter を記述
`server/middleware.router.ts` を以下の通りにする

```typescript:server/middleware.router.ts
import KoaRouter = require('koa-router');

import SampleContoroller = require('./app/controller/sample.controller');

/** 仮リクエスト */
interface Request {
    requestId: string;
}
/** 仮レスポンス */
interface Response {
    status: boolean;
    statusCode: number;
}

/** ミドルウェア ルータ */
class MiddlewareRouter {
    /** 各ルータを束ねたミドルウェアを生成 */
    public routes(): KoaRouter.IMiddleware {
        const koaRouter = new KoaRouter();
        koaRouter.get('/', function (ctx) {
            ctx.body = 'Hello, Koa!!';
            console.log('=== Hello, Koa!! ===');
        });

        koaRouter.get('/api/get-sample', this.callGet(new SampleContoroller().test));

        return koaRouter.routes();
    }

    /**
     * 実行処理の呼び出し(GET)
     * @param controll 実行される処理
     * @returns ルータに設定するミドルウェア
     */
    private callGet(controll: (request: Request) => Promise<Response>): any {
        return async function(ctx: KoaRouter.IRouterContext) {
            const ctxRequest: any = ctx.request;
            const ctxResponse = await controll(ctxRequest.query);
            ctx.body = ctxResponse;
        };
    }
}
export = MiddlewareRouter;

```

## server.ts を修正
`server/server.ts` を以下の通りに修正する

```typescript:server/server.ts
// アプリケーションサーバ起動設定
import Koa = require('koa');
import bodyparser = require('koa-bodyparser');
import MiddlewareRouter = require('./middleware.router');

const app = new Koa();

// サーバ側ミドルウェアの提供
app.use(bodyparser({
    extendTypes: {
        json: ['application/x-javascript']
    }
}))
.use(new MiddlewareRouter().routes());

// サービス開始
const port = 3000;
app.listen(port, () => console.log(`App is listing port in ${port}`));

```

## 動作確認
* `npm run start` でサーバ（server.ts）を起動し、コンソール上に「`App is listing port in 3000`」と表示されたら`http://localhost:3000` でサンプルページ表示し、画面に「Hello, Koa!!」と表示され、かつ、コンソール上に「`=== Hello, Koa!! ===`」と表示されたら成功。
* `http://localhost:3000/api/get-sample` と打ち込み、画面に「`{status: true, statusCode: 200, result: 1}`」と表示され、かつ、コンソール上に以下のとおりにレスポンスが表示されたら成功。

```
=== SampleContoroller # test ===
{ }
```

* 動作確認できたら `Ctrl + C` でサーバ終了。

---

ここまでが バックエンドの初期設定。

→ [次に、クラサバ間の通信部分を構築をする](https://qiita.com/tomy0610/items/f43f75df060da71c09e4)