Serverless Framework v1.0のlambda-proxyを使って任意のレスポンスを返す

Serverless Framework v1.0で追加されたlambda-proxyを使ってHTTPステータスコードの操作と、任意のレスポンスを返してみたいと思います。
rc.2までのエラー操作はLabmda上で生成したエラーオブジェクトのmessageにセットしたJson文字列をマッピングテンプレートのVLTでパースしてエラー時の文言を生成していました。
以前までのエラーハンドリングのベストプラクティスに関してはこちらの記事で詳しく紹介されています。
[Error Handling Patterns in Amazon API Gateway and AWS Lambda](https://aws.amazon.com/jp/blogs/compute/error-handling-patterns-in-amazon-api-gateway-and-aws-lambda/)

lambda-proxyを使えば、こういった面倒くさい設定をせずにLambda内で返却するレスポンスの設定が可能となります。

## 動作環境
* Serverless Framework v1.0.2
* nodejs v4.3.2

Serverlessの基本的なセットアップについては、[Serverless Framework v1.0の使い方まとめ](http://qiita.com/horike37/items/b295a91908fcfd4033a2)で詳しく書かれていますので、そちらを参考にしてください。

## レスポンスオブジェクトの基本的な構造

レスポンス時に渡すオブジェクトの基本は以下のような構造になっています。

```
{
  statusCode: 200,    // HTTPステータスコード
  headers: {
    'x-custom-header' : 'My Header Value'    // レスポンスヘッダ
  },
  body: JSON.stringify('hello serverless')    // レスポンスボディ
}
```
HTTPステータスコード、レスポンスヘッダ、レスポンスボディの３つで構成されます。
たいした説明は必要無さそうですが、レスポンスヘッダに`Content-Type`未指定時はデフォルトで`application/json`などの暗黙的な挙動があるので、動作確認しつつ確認してください。

詳細は公式ドキュメントの[lambda-proxy](https://github.com/serverless/serverless/blob/master/docs/02-providers/aws/events/01-apigateway.md#lambda-proxy)を読んでください

## HTTPレスポンス200（正常系）を返す

最も一般的なレスポンスになるかと思います。
プロジェクト作成時のサンプルでデフォルトで生成される内容とほぼ同等です。

```
module.exports.ok = (event, context, callback) => {
  const response = {
    statusCode: 200,
    body: JSON.stringify({message: 'Go Serverless v1.0! Your function executed successfully!'})
  };
  return callback(null, response);
};
```

特に説明もいらないとは思いますが、 
`{"message":"Go Serverless v1.0! Your function executed successfully!"}`
というレスポンスを返します。
デフォルトの`Content-Type`が`application/json`なので、`Content-Type`未指定時にはbodyにJson文字列を渡してあげましょう。

## HTTPレスポンスコード400（バリデーションエラー）を返す

```
module.exports.badrequest = (event, context, callback) => {
  const errors = {
    email: 'email require',
    password: 'must have length greater than or equal to 6'
  }
  const response = {
    statusCode: 400,
    body: JSON.stringify(errors)
  };
  return callback(null, response);
};
```
Lambda上で入力チェックをした際に、バリデーションエラーとしてエラー内容の詳細を返す場合などに便利です。
ajax経由で呼び出した場合のレスポンスには、`jqXHR.responseJSON`内にこのオブジェクトが格納されるので、このオブジェクトをパースしてエラー処理を行います。

Lambda上で成功とエラーを綺麗に分けたい場合は `callback(new Error('[400] Bad Request'));` のように返し、serverless.ymlで[ステータスコードをカスタムする](https://github.com/serverless/serverless/blob/master/docs/02-providers/aws/events/01-apigateway.md#status-codes) ことが推奨されていますが、今回は割愛します。

## HTTPレスポンスコード302（リダイレクト）を行う

```
module.exports.redirect = (event, context, callback) => {
  const response = {
    statusCode: 302,
    headers: {
      'Location': 'https://google.co.jp/'
    }
  };
  return callback(null, response);
};
```

リダイレクトを行います。
以前までは、[serverless-plugin-multiple-responses](https://github.com/silvermine/serverless-plugin-multiple-responses) 等のプラグインを利用しないとできなかったリダイレクト処理も可能になりました。
※　`response`オブジェクト内に、`body`を定義すると動作しないので注意してください。

## htmlコンテンツを返す

```
module.exports.html = (event, context, callback) => {
  const response = {
    statusCode: 200,
    headers: {
      'Content-Type': 'text/html;charset=UTF-8'
    },
    body: '<!DOCTYPE html><html lang="ja"><title>serverless-response-sample</title><body><h1>html response</h1><p>hello serverless!</p></body></html>'
  };
  return callback(null, response);
};
```

デフォルトでは`Content-Type: application/json`を返していましたが、`Content-Type: text/html`を指定することでhtmlコンテンツも返却可能です。
これを上手く使えば、ある程度の動的コンテンツの生成もできそうですね。

## 最後に

今まで、VLTで記述したマッピングテンプレートを駆使してレスポンスの変換も行ってきたわけですが、これらがすべてLambda上で設定可能となりました。
serverless.yml の記述量も減り、保守のしやすさなども向上したのではないでしょうか。
今後もどういった進化を遂げていくのか楽しみですね。

今回のコードはgithubでも公開していますので、Serverless Framework採用時の足がかりにでもなればと思います。
[github](https://github.com/quartette/serverless-response-sample)