[Serverless Framework] Middy Router

# Middyの紹介
MiddyはNode.jsをベースにしたAWS Lambda関数のリクエスト処理を簡素化および改善するために登場したフレームワークです。現在のバージョンでは、Http RouterやWebSocket Routerなどの機能が存在します。これにより、複数のAPIエンドポイントを単一のLambda関数に統合することが可能となり、リソースの効率的な管理が可能です。

> https://middy.js.org/

# Middyの登場背景
- **サーバーレスアーキテクチャの登場**
クラウドコンピューティングの発展と共に、AWS Lambdaのようなサービスはサーバーの管理なしでコードを実行できるようにし、開発者がインフラ管理よりもビジネスロジックに集中できるようにしました。
- **機能の制限**
AWS Lambdaは非常に便利ですが、複雑なルーティング、リクエストのパース、エラーハンドリングなどを処理するためには追加のロジックが必要でした。
- **重複コードの問題**
サーバーレス関数間で共通して必要な機能を各関数に繰り返し記述することが多く、これは保守性を低下させ、エラーの可能性を高めます。

# Middy Http Routerの登場
- **ルーティングの簡素化**
Middy Http Routerは複雑なAPIエンドポイントの管理を簡素化するため、Httpリクエストをそれぞれの処理ロジックにルーティングする機能を提供します。これは、Serverless-Expressに似た機能です。

- **コードの再利用および簡素化**
共通のリクエスト処理ロジックをミドルウェアとして分離し、コードの重複を減らして簡潔なロジックを作成することができます。

- **サーバーレス環境の最適化**
Lambdaのようなサーバーレス環境でHttpリクエストを効果的に処理することができます。

# CloudFormationの制約とSplit Stackの利用
CloudFormationにはデプロイするリソースの数に制限（500個）があるため、Serverless FrameworkのSplit Stackのように、多くのリソースを一度にデプロイする方法がよく採用されてきました。しかし、Split Stackを使用すると、その分デプロイ時間が長くなるという問題があり、これはDevOps担当者にとって大きな悩みの種でした。

# Middy 4.0のHttp Routerの利点
Middy 4.0バージョン以降では、Http Routerを提供しており、単一のLambdaに複数のAPIを統合する機能を提供しています。以前はこの問題を解決するために、API Gatewayでワイルドカード{Proxy+}を使用して動的にルーティングを行うLambdaを作成していましたが、現在ではMiddyがこの機能を提供しているため、多くのデプロイリソースを削減できるようになりました。

## コードの例
以下のソースコードの例を見てみると、ハンドラー内で各リクエストに応じた実行ハンドラーを登録し、それを実行しています。実際のところ、VendiaのServerless-Expressも同様の原理で動作します。しかし、MiddyとServerless-Expressの決定的な違いは、AWSに対する親和性が高いのはMiddyの方であるという点です。

``` js
import middy from '@middy/core'
import httpRouterHandler from '@middy/http-router'
import validatorMiddleware from '@middy/validator'

const getHandler = middy()
  .use(validatorMiddleware({eventSchema: {...} }))
  .handler((event, context) => {
    return {
      statusCode: 200,
      body: '{...}'
    }
  })

const postHandler = middy()
  .use(validatorMiddleware({eventSchema: {...} }))
  .handler((event, context) => {
    return {
      statusCode: 200,
      body: '{...}'
    }
  })

const routes = [
  {
    method: 'GET',
    path: '/user/{id}',
    handler: getHandler
  },
  {
    method: 'POST',
    path: '/user',
    handler: postHandler
  }
]

export const apiHandler = middy()
  .use(httpHeaderNormalizer())
  .handler(httpRouterHandler(routes))
```
ルーティングの方法については、以下の例を参照してください。
```yml
functions:
  apiHandler:
    handler: handler.apiHandler
    events:
      - http:
          path: /
          method: ANY
      - http:
          path: /{proxy+}
          method: ANY
```

また、以下の例のようにルーティングするパスを直接指定する方法もあります。この場合、HTTPパスが変更されると、CloudFormationが更新される際にクラッシュする問題が発生する可能性があるため注意が必要です。通常、API Gatewayをコンソールから直接指定した場合とIaC（Infrastructure as Code）方式で更新する場合が衝突することで、上記のようなクラッシュ現象が多く発生します。このような場合は、いずれかの方法に統一して再デプロイすることで解決できます。

``` yml
functions:
  apiHandler:
    handler: handler.apiHandler
    events:
      - http:
          path: /user/{id}
          method: GET
      - http:
          path: /user
          method: GET
      - http:
          path: /user
          method: POST
```

# Serverless-Expressとの違い
Serverless-ExpressはAWS Lambda上でExpress.jsを実行するためのプロジェクトです。これは、JavaのSpringBootやSpring Cloud FunctionをAWS Lambda上で動かすのと似ています。しかし、決定的な違いは、Serverless-ExpressはLambda Invokeを許可しない点です。そのため、Cold Startの問題点があると言えますが、Middy Http Routerはこの問題を克服することができます。