[Node.js] Express を TypeScript で書く - ルーティング編


# はじめに

一応、前回の記事の続きとなっております。

- [[Node.js] Express を TypeScript で書く - 環境整備まで](https://qiita.com/kuroneko8960/items/74347b6a58020f33b18d)

環境は以下を前提としてます。

- Windows 10
- Node.js 10.10.0
- Express 4.16.3
- TypeScript 3.0.3
- Visual Studio Code 1.26.1

# 準備

ルーティングを書く前に下準備をします。

## 今回設計するAPI

今回は別に外部に公開するわけでもなく、練習用なので最小限な感じで考えます。
必要な機能としては、以下の通り。

- ユーザ作成、参照
- ログイン、ログアウト
- 記事の取得、一覧、投稿、検索

これらをAPIとしてURLに起こして行きます。

## ダミーコードの準備

今回はルーティングの実装は書かず、ルーティングだけ先に実装する流れで作りたいので、リクエストしたらエラーを返すだけのダミーコードを用意します。

```ts:src/noImpl.ts
import * as Express from 'express';

export default function notImplemented(req: Express.Request, res: Express.Response, next: Express.NextFunction) {
    res.status(501).json({ message: 'Not Implemented.' });
}
```

# コードを書く

思考錯誤しながら書いて最終的には以下の通りにまとまりました。
基本、CRUDを意識しつつ、API１つ１つがユニークになるように。

このへんはTypeScriptだからといって書き方に差異が出る所はあまりないと思います。

```ts:src/routes/articles/index.ts
import * as Express from 'express';
import noImpl from '../../noImpl';

const router = Express.Router();

// 全ユーザの記事一覧取得
router.get('/', noImpl);

// ログインしてるユーザの記事投稿
router.post('/', noImpl);

export default router;
```

```ts:src/routes/auth/index.ts
import * as Express from 'express';
import noImpl from '../../noImpl';

const router = Express.Router();

// ログイン処理
router.post('/login', noImpl);

// ログアウト処理
router.delete('/logout', noImpl);

// article 自体の READ, UPDATE, DELETE は /user/:user/article で行うようにする。

export default router;
```

```ts:src/routes/user/index.ts
import * as Express from 'express';
import noImpl from '../../noImpl';
import article from './article';

const router = Express.Router();

// ユーザの新規作成
router.post('/new', noImpl);

// ユーザ情報の取得
router.get('/:user', noImpl);

// ユーザの情報更新
router.put('/:user', noImpl);

// ユーザの削除
router.delete('/:user', noImpl);

// ユーザ毎の記事表示用ルーティング
router.use('/:user/article', article);

export default router;
```

`user/article/index.ts` では 子のパラメーターも使えるようにしたいので `Express.Router({ mergeParams: true })` の指定をしています。

```src/routes/user/article/index.ts
import * as Express from 'express';
import noImpl from '../../../noImpl';

const router = Express.Router({ mergeParams: true });

// ユーザの記事一覧
router.get('/list', noImpl);

// 記事単体取得
router.get('/:article', noImpl);

// 記事の更新
router.put('/:article', noImpl);

// 記事の削除
router.delete('/:article', noImpl);

export default router;
```

各々の記述が終わったら `src/server.ts` を直します。

```ts:src/server.ts
import * as Express from 'express';
import expressListEndpoints from 'express-list-endpoints';
import article from './routes/article';
import auth from './routes/auth';
import user from './routes/user';

const app = Express();

app.use('/article', article);
app.use('/auth', auth);
app.use('/user', user);

app.listen(3000, () => {
    console.log('Listen started at port 3000.');
    console.log(expressListEndpoints(app));
});

export default app;
```

実装したルーティングの確認用に新たに `express-list-endpoints` モジュールを導入してます。ルーティングの一覧をオブジェクトとして返してくれます。

```bash
npm install --save express-list-endpoints 
```

# 実行

ここまでのをビルドして実行すると `express-list-endpoints` によってコンソールに以下のように表示されます。

```bash
[ { path: '/article', methods: [ 'GET' ] },
  { path: '/article', methods: [ 'POST' ] },
  { path: '/auth/login', methods: [ 'POST' ] },
  { path: '/auth/logout', methods: [ 'DELETE' ] },
  { path: '/user/new', methods: [ 'POST' ] },
  { path: '/user/:user', methods: [ 'GET' ] },
  { path: '/user/:user', methods: [ 'PUT' ] },
  { path: '/user/:user', methods: [ 'DELETE' ] },
  { path: '/user/:user/article/list', methods: [ 'GET' ] },
  { path: '/user/:user/article/:article', methods: [ 'GET' ] },
  { path: '/user/:user/article/:article', methods: [ 'PUT' ] },
  { path: '/user/:user/article/:article', methods: [ 'DELETE' ] } ]
```

環境によってはヘルスチェックのためにルートに200を返すだけのコードも必要になってくるのですが、今回は省略。

次回は mongoDB 導入、接続編です。

[[Node.js] Express を TypeScript で書く - MongoDB 接続編](https://qiita.com/kuroneko8960/items/fa8665017d98774d3c06)