Amazon Alexa Skill Kit のリクエストを紐解く

# はじめに

Alexa Skillの開発をする際には、送信されたJSONを使って各種処理を行います。
今回は送信されたJSONを1つずつ紐解いてみたいと思います
ただ・・・調べている途中にAmazonの公式のドキュメントに詳細にかかれていることに気が付きました。。。
書きかけだったのと、公式ドキュメントより具体的に書いている部分もあるので自分のメモも兼ねて公開しておきます。

[カスタムスキルのJSONインターフェースのリファレンス \| Custom Skills](https://developer.amazon.com/ja/docs/custom-skills/request-and-response-json-reference.html)

# Alexa Request JSON

Alexaから送信されるJSONは下記です。

```
{
  "session": {
    "new": true,
    "sessionId": "SessionId.xxx",
    "application": {
      "applicationId": "amzn1.ask.skill.xxx"
    },
    "attributes": {},
    "user": {
      "userId": "amzn1.ask.account.xxx",
      "accessToken": "xxx",
      "permissions": {
        "consentToken": "xxx"
      }
    }
  },
  "request": {
    "type": "IntentRequest",
    "requestId": "EdwRequestId.xxx",
    "intent": {
      "name": "HelloWorldIntent",
      "slots": {}
      }
    },
    "locale": "ja-JP",
    "timestamp": "2018-03-15T23:30:55Z"
  },
  "context": {
    "AudioPlayer": {
      "playerActivity": "IDLE"
    },
    "System": {
      "application": {
        "applicationId": "amzn1.ask.skill.xxx"
      },
      "user": {
        "userId": "amzn1.ask.account.xxx"
      },
      "device": {
        "supportedInterfaces": {}
      }
    }
  },
  "version": "1.0"
}
```

項目ごとに詳細に説明します。

## session.new

このセッションが新しいセッションかどうかの値を返します。値は`true`　or　`false`です。
例えばAlexaに、続きの発話を要求したい場合にはセッションが継続する旨のレスポンスを返します。
その場合にはAlexaデバイスは発話待ちの状態になります。
発話待ちの状態から新しい発話を受け取ると`false`としてリクエストが飛んできます。

例えば下記のような発話例の場合には「1」のリクエストは`true`で、「3」のリクエスでは`false`となります。

```
# 発話例
1. 自分：　Alexa、プロフィールを起動して　【true】
2. Alexa：　あなたの名前を教えてください
3. 自分：　とちひら です　【false】
4. Alexa：　あなたの年齢を教えてください
5. 自分：　39歳 です　【false】
6. Alxa： とちひら さんの年齢は 39歳 ですね
```

## session.sessionId

セッションごとのユニークなIDです。
公式ドキュメントにも書かれていますが、続き（session.new 発話例の様に続いている）の場合にはセッションIDは同一となります。

## session.application.applicationId

Alexa SkillごとのユニークなIDです。
`applicationId`は正しいAlexa Skillからのリクエストなのかを検証する際に利用します。

[サービスに対するリクエストの妥当性を検証する \| Custom Skills](https://developer.amazon.com/ja/docs/custom-skills/handle-requests-sent-by-alexa.html#%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AB%E5%AF%BE%E3%81%99%E3%82%8B%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%AE%E5%A6%A5%E5%BD%93%E6%80%A7%E3%82%92%E6%A4%9C%E8%A8%BC%E3%81%99%E3%82%8B)

## session.attributes

Alexaで継続して発話を受け付けている場合に、以前の発話の値を次の発話まで保持したい場合があります。
その際にキーと値のペアで`attributes`にセットしてあげることで、次の発話で値を取り出すことが可能になります。

```
# 発話例
1. 自分：　Alexa、プロフィールを起動して
2. Alexa：　あなたの名前を教えてください
3. 自分：　とちひら です　【「とちひら」をセット】
4. Alexa：　あなたの年齢を教えてください
5. 自分：　39歳 です
6. Alxa： とちひらさんの年齢は39歳ですね　【「とちひら」を取り出し】
```

## session.user.userId

ユーザーごとのユニークなIDです。
`userId`はスキルを有効にするとAmazonアカウントごとに割り振られます。
例えば複数のAlexaデバイスで、同じAmazonアカウントでスキルを利用している場合には`userId`は同じになります。
スキルを`有効=>無効=>有効`とした場合には新しい`userId`が付与されます。

例えば初回利用時にニックネームを登録してもらいます。
2回目からはニックネームで呼びかけるような場合に`userId`をキーとしてニックネームを保持することも可能です。

## session.user.accessToken

AlexaがOAuthで外部サービスとアカウント連携した場合に必要となる`accessToken`です。

[Alexaユーザーとシステムユーザーを関連付ける \| Custom Skills](https://developer.amazon.com/ja/docs/custom-skills/link-an-alexa-user-with-a-user-in-your-system.html)

## session.user.permissions.consentToken

Alexaには、住所やTODOリストを登録する仕組みがあります。
これらの個人情報にスキルからアクセスする事が可能です。
アクセスする際に`consentToken`を利用して個人情報を取得します。

[所在地情報を使用してスキルを拡張する \| Custom Skills](https://developer.amazon.com/ja/docs/custom-skills/device-address-api.html)

[Alexaの買い物リストとTo Doリストにアクセスする \| Custom Skills](https://developer.amazon.com/ja/docs/custom-skills/access-the-alexa-shopping-and-to-do-lists.html)

## request.type

リクエストの種類です。
インテントの指定が無い場合には`LaunchRequest`が、インテントの指定がある場合には`IntentRequest`が入ります。
`IntentRequest`はスキルを作っていれば自然と実装しますが、`LaunchRequest`は忘れがちです。ただ、`LaunchRequest`を実装していない場合には審査に通りません。（僕も審査に提出した際に指摘されました。）

[標準のリクエストタイプのリファレンス \| Custom Skills](https://developer.amazon.com/ja/docs/custom-skills/request-types-reference.html)

## request.requestId

`requestId`は1リクエストごとに異なります。
連続した発話であっても、各リクエストごとに異なる`requestId`が入ります。

## request.intent.name

スキルを作成する場合には、該当の発話がされると該当のインテントが呼ばれるように設定します。
その該当のインテント名が入ります。
例えば、「こんにちは」と発話された場合に`HelloIntent`を設定している場合には`request.intent.name`には`HelloIntent`が入ります。

## request.intent.slots

発話の中の単語を取得した場合があります。
例えば「私の名前は とちひら です」と発話された場合に名前の部分を取り出して利用したいときがあります。
この時に利用できるのが`slots`です。スロットはキーと値のペアでデータが入っています。
キーを`firstName`、値を`とちひら`とした場合のスロットは下記の様になります。
`"slots"=>{"firstName"=>{"name"=>"firstName", "value"=>"とちひら"}}`

## request.locale

スキルを多言語対応する利用します。Alexaデバイスに設定されているロケールが入ります。
日本語の場合には`ja-JP`です。

## request.timestamp

タイムスタンプが入ります。タイムスタンプはリプレイ攻撃を防ぐために検証する必要があると書かれています。

[リクエストのタイムスタンプを確認する \| Custom Skills](https://developer.amazon.com/ja/docs/custom-skills/host-a-custom-skill-as-a-web-service.html#timestamp)

## context.System.application.applicationId

`session.application.applicationId`と同じ値が入ります。
ここだけ`System`が頭文字が大文字なのが気になります。。。値を取るときにも気をつけましょう。

## context.System.user.userId

`session.user.userId`と同じ値が入ります。

## version

Alexaのバージョンが入ります。現在は`1.0`のみです。

# まとめ

リクエストの中身も随時追加されているようです。
できる限り更新していきたいと思いますので、不足や間違いがあれば指摘頂けると助かります。