ClovaスキルをLambdaで開発し始める時の手順をまとめた(Node.js)

# はじめに

Clovaスキルを開発するときに最初に行うことをまとめたものです。
環境は以下を前提にしています。

* エンドポイントはAWS Lambda
* node.js(8.10)
* 開発には[公式SDK](https://github.com/line/clova-cek-sdk-nodejs)を使用

# プロジェクト作成

```
$ git init
$ npm init
# layerを使用する場合は以下の2つは省略
$ npm install --save @line/clova-cek-sdk-nodejs aws-sdk
$ npm install --save @line/bot-sdk #botを使う場合
```

# .gitignore

```:.gitignore
upload.zip
node_modules
```


# index.js

```js:index.js
/*
https://github.com/line/clova-cek-sdk-nodejs
*/

const clova = require("@line/clova-cek-sdk-nodejs");
const line = require('@line/bot-sdk');

const clovaSkillHandler = clova.Client
  .configureSkill() 
  .onLaunchRequest(responseHelper => {

    // sessionAttributesを明示的にクリア
    responseHelper.setSessionAttributes({})

    responseHelper.setSimpleSpeech(
      clova.SpeechBuilder.createSpeechText(`LaunchRequestで喋らせたい内容`)
    );
  })
  .onIntentRequest(async responseHelper => {
    const intent = responseHelper.getIntentName();
    const sessionId = responseHelper.getSessionId();

    switch (intent) {
      case "SmapleIntent":
        responseHelper.setSimpleSpeech(
          clova.SpeechBuilder.createSpeechText(`Clovaが喋る内容`)
        );
        break;
      case "Clova.GuideIntent":
        break;
      case "Clova.YesIntent":
        break;
      case "Clova.NoIntent":
        break;
    }
  })
  .onSessionEndedRequest(responseHelper => {
    responseHelper.endSession();

  })

exports.handler = clovaSkillHandler.lambda()
/*
handlerを以下にするとリクエストのログを取れる
*/

/*
exports.handler = async (event, content) => {
  console.log("event: " + JSON.stringify(event));

  var ctx = new clova.Context(event);
  const requestType = ctx.requestObject.request.type;
  const requestHandler = clovaSkillHandler.config.requestHandlers[requestType];

  if (requestHandler) {
    await requestHandler.call(ctx, ctx);
  }

  return ctx.responseObject;
};
*/
```

# 検証を行う場合

本当にCEKからきたアクセスかを検証します。
別にしなくてもいいよって方は飛ばしてください。

最後の以下の１行を変更します。

```js:変更前
exports.handler = clovaSkillHandler.lambda()
```

```js:変更後
exports.handler = async (event, content) => {
  console.log("--- event ---");
  console.log(util.inspect(event), false, null);

  const signature = event.headers.signaturecek || event.headers.SignatureCEK;
  const applicationId = process.env["applicationId"];
  const requestBody = event.body;
  // 検証
  // リクエストが自分の作成したスキルからであるか等を確認しています。
  await clova.verifier(signature, applicationId, requestBody);
  console.log("clear verifier");

  var ctx = new clova.Context(JSON.parse(event.body));
  const requestType = ctx.requestObject.request.type;
  const requestHandler = clovaSkillHandler.config.requestHandlers[requestType];

  if (requestHandler) {
    await requestHandler.call(ctx, ctx);

    // CEKに返すレスポンスです。
    // API Gatewayの設定で「Lambdaのプロキシ結合の使用」のチェックを入れた場合、
    // レスポンスにヘッダー等を入れる必要がある
    const response =  {
      "isBase64Encoded": false,
      "statusCode": 200,
      "headers": {},
      "body": JSON.stringify(ctx.responseObject),
    }

    console.log(util.inspect(response), false, null);

    return response;
  } else {
    throw new Error(`Unable to find requestHandler for "${requestType}"`);
  }
}
```

環境変数に以下を追加します。

* 変数名: applicationId
* 値: CEKで設定したExtensionID

AWS　APIGatewayで`Lambda プロキシ統合の使用`のチェックを入れます。
何それ？って方は[こちら](https://qiita.com/imajoriri/items/b67318cfda04998255b8#%E3%81%97%E3%81%8B%E3%83%BC%E3%81%97%E6%A4%9C%E8%A8%BC%E3%82%92%E3%81%97%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84)の記事を参考にしてください。


# Lambda layerを作成する場合

layerを使用すると、SDK等のインストールを毎回行わずに済みます。
開発効率を上げるたい場合は、使用することをお勧めします。
詳しくは以下を参照してください
[（新機能）Lambda LayerでAlexa SDK V2を使ってみたら、超便利だった](https://dev.classmethod.jp/cloud/aws/reinvent2018-lambda-layer-alexa-sdk-v2/)

```
$ mkdir nodejs #nodejsといるディレクトリじゃないと動きません。
$ cd nodejs
$ npm init
$ npm install --save @line/clova-cek-sdk-nodejs aws-sdk
$ npm install --save @line/bot-sdk
$ cd ../
$ zip -r upload.zip nodejs/
```

layerを使用する場合は　sdkのインストールは省略します。