リクエスト処理



リクエスト処理

標準のリクエスト

作成したスキルサービスとAlexaとの通信は、SSL/TLSを利用してHTTPを使用するリクエスト-応答メカニズムで行います。ユーザーがAlexaスキルと対話するとき、作成したサービスは、JSON本文を含むPOSTリクエストを受け取ります。このリクエスト本文には、サービスがロジックを実行してJSON形式の応答を生成するために必要なパラメーターが含まれています。Node.jsはネイティブにJSONを処理できるため、ASK SDK v2 for Node.jsではJSONのシリアル化と逆シリアル化が必要ありません。リクエスト本文のJSON構造についてのドキュメントは、こちらを参照してください。

ハンドラー入力

リクエストハンドラー、リクエストと応答のインターセプター、エラーハンドラーにはすべて、呼び出し時にHandlerInputオブジェクトが渡されます。このオブジェクトには、リクエスト処理に有効な各種エンティティが含まれます。以下はその例です。

  • RequestEnvelope: スキルに送信されるリクエスト本文全体を含みます。
  • ResponseBuilder: 応答を作成するヘルパーメソッドを含みます。詳細については、応答のビルドを参照してください。
  • AttributesManager: リクエスト、セッション、永続アトリビュートへのアクセスを提供します。詳細については、アトリビュートの管理を参照してください。
  • ServiceClientFactory: Alexa APIの呼び出しが可能なサービスクライアントを構築します。詳細については、AlexaサービスAPIの呼び出しを参照してください。
  • Context: ホストコンテナが渡す任意のcontextオブジェクトを提供します。たとえばAWS Lambdaで実行されるスキルの場合、AWS Lambdaメソッドのcontextオブジェクトになります。

リクエストハンドラー

リクエストハンドラーは、受け取った1つ以上のタイプのリクエストを処理します。リクエストハンドラーの作成には、RequestHandlerインターフェースを使用できます。このインターフェースは以下の2つのメソッドで構成されています。

  • canHandleは、SDKによって呼び出され、指定されたハンドラーが受け取ったリクエストを処理できるかどうかを判断します。このメソッドは、HandlerInputオブジェクトを受け取り、ハンドラーがリクエストを処理できる場合はtrue、処理できない場合はfalseを返します。受信するリクエストのタイプやパラメーター、スキルのアトリビュートなど、この判断を行うための条件を選択できます。
  • handleは、リクエストハンドラーを呼び出すときにSDKによって呼び出されます。このメソッドには、ハンドラーのリクエスト処理ロジックが含まれます。また、HandlerInputを受け取り、ResponseまたはPromise<Response>を返します。

インターフェース

interface RequestHandler {
    canHandle(handlerInput: HandlerInput): Promise<boolean> | boolean;
    handle(handlerInput: HandlerInput): Promise<Response> | Response;
}

サンプルコード

以下は、HelloWorldIntentを処理できるリクエストハンドラーの例です。

クリップボードにコピーされました。

const HelloWorldIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
  },
  handle(handlerInput) {
    const speechText = 'こんにちは';

    return handlerInput.responseBuilder
      .speak(speechText)
      .withSimpleCard('ハローワールド', speechText)
      .getResponse();
  }
};

クリップボードにコピーされました。

import {
  HandlerInput,
  RequestHandler,
} from 'ask-sdk-core';
import { Response } from 'ask-sdk-model';

const HelloWorldIntentHandler : RequestHandler = {
  canHandle(handlerInput : HandlerInput) : boolean {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
  },
  handle(handlerInput : HandlerInput) : Response {
    const speechText = 'こんにちは';

    return handlerInput.responseBuilder
      .speak(speechText)
      .withSimpleCard('ハローワールド', speechText)
      .getResponse();
  },
};

canHandleメソッドは、受け取るリクエストがIntentRequestかどうかを検出し、インテント名がHelloWorldIntentの場合にtrueを返します。handleメソッドは、基本的な「こんにちは」という応答を生成して返します。

以下の例は、SDKを使ってリクエストハンドラーを登録する方法を示しています。

クリップボードにコピーされました。

const Alexa = require('ask-sdk-core');

const skill = Alexa.SkillBuilders.custom()
  .addRequestHandlers(
    FooHandler,
    BarHandler,
    BazHandler)
  .create();

クリップボードにコピーされました。

import { SkillBuilders } from 'ask-sdk-core';

const skill = SkillBuilders.custom()
  .addRequestHandlers(
    FooHandler,
    BarHandler,
    BazHandler)
   .create();

リクエストと応答のインターセプター

SDKは、RequestHandlerの実行前と実行後に実行するリクエストと応答のインターセプターをサポートします。インターセプターは、RequestInterceptorインターフェースかResponseInterceptorインターフェースを使用して実装できます。

どちらのインターセプターインターフェースも、戻り値の型がvoidであるprocessメソッドを1つ実行します。リクエストのインターセプターはHandlerInputオブジェクトにアクセスでき、応答のインターセプターはHandlerInputと、RequestHandlerによって生成されるオプションのResponseにアクセスできます。

インターフェース

interface RequestInterceptor {
    process(handlerInput: HandlerInput): Promise<void> | void;
}

interface ResponseInterceptor {
    process(handlerInput: HandlerInput, response?: Response): Promise<void> | void;
}

リクエストのインターセプターは、受け取るリクエストのリクエストハンドラーが実行される直前に呼び出されます。リクエストアトリビュートは、リクエストのインターセプターがリクエストハンドラーにデータやエンティティを渡す方法を提供します。

応答のインターセプターは、リクエストハンドラーが実行された直後に呼び出されます。応答のインターセプターはリクエストハンドラーを実行して生成される出力結果にアクセスできるため、応答のサニタイズや検証といったタスクに適しています。

サンプルコード

以下は、応答がAlexaに送信される前に永続アトリビュートのデータベースへの保存を処理する応答のインターセプターの例です。

クリップボードにコピーされました。

const PersistenceSavingResponseInterceptor = {
  process(handlerInput) {
    return new Promise((resolve, reject) => {
      handlerInput.attributesManager.savePersistentAttributes()
        .then(() => {
          resolve();
        })
        .catch((error) => {
          reject(error);
        });
    });
  }
};

クリップボードにコピーされました。

import {
  HandlerInput,
  ResponseInterceptor,
} from 'ask-sdk-core';

const PersistenceSavingResponseInterceptor : ResponseInterceptor = {
  process(handlerInput : HandlerInput) : Promise<void> {
    return handlerInput.attributesManager.savePersistentAttributes();
  },
};

以下の例は、SDKを使ってインターセプターを登録する方法を示しています。

クリップボードにコピーされました。

const Alexa = require('ask-sdk-core');

const skill = Alexa.SkillBuilders.custom()
  .addRequestHandlers(
    FooHandler,
    BarHandler,
    BazHandler)
  .addRequestInterceptors(
    FooRequestInterceptor,
    BarRequestInterceptor)
  .addResponseInterceptors(
    FooResponseInterceptor,
    BarResponseInterceptor)
  .create();

クリップボードにコピーされました。

import { SkillBuilders } from 'ask-sdk-core';

const skill = SkillBuilders.custom()
  .addRequestHandlers(
    FooHandler,
    BarHandler,
    BazHandler)
  .addRequestInterceptors(
    FooRequestInterceptor,
    BarRequestInterceptor)
  .addResponseInterceptors(
    FooResponseInterceptor,
    BarResponseInterceptor)
  .create();

エラーハンドラー

エラーハンドラーはリクエストハンドラーに似ていますが、リクエストではなく1つまたは複数のタイプのエラーを処理します。リクエストの処理中に未処理のエラーがスローされると、SDKがエラーハンドラーを呼び出します。

すべてのエラーハンドラーは、ErrorHandlerインターフェースを使用する必要があります。このインターフェースは以下の2つのメソッドで構成されています。

  • canHandleは、SDKによって呼び出され、指定されたハンドラーがエラーを処理できるかどうかを判断します。ハンドラーがエラーを処理できる場合はtrue、処理できない場合はfalseを返します。catch-allハンドラーを作成する場合は常にtrueを返します。
  • handleは、エラーハンドラーを呼び出すときにSDKによって呼び出されます。このメソッドにはエラー処理ロジックがすべて含まれ、ResponseまたはPromise<Response>を返します。

インターフェース

interface ErrorHandler {
    canHandle(handlerInput: HandlerInput, error: Error): Promise<boolean> | boolean;
    handle(handlerInput: HandlerInput, error: Error): Promise<Response> | Response;
}

サンプルコード

以下は、名前が「AskSdk」で始まるエラーをすべて処理できるエラーハンドラーの例です。

クリップボードにコピーされました。

const myErrorHandler = {
  canHandle(handlerInput, error) {
    return error.name.startsWith('AskSdk');
  },
  handle(handlerInput, error) {
    return handlerInput.responseBuilder
      .speak('リクエストの処理中にエラーが発生しました。後でもう一度お試しください。')
      .getResponse();
  }
};

クリップボードにコピーされました。

import { HandlerInput } from 'ask-sdk-core';
import { Response } from 'ask-sdk-model';

const myErrorHandler = {
  canHandle(handlerInput : HandlerInput, error : Error) : boolean {
    return error.name.startsWith('AskSdk');
  },
  handle(handlerInput : HandlerInput, error : Error) : Response {
    return handlerInput.responseBuilder
      .speak('リクエストの処理中にエラーが発生しました。後でもう一度お試しください。')
      .getResponse();
  },
};

ハンドラーのcanHandleメソッドは、受け取るエラーの名前が「AskSdk」で始まる場合にtrueを返します。handleメソッドは、ユーザーに正常なエラー応答を返します。

以下の例は、SDKを使ってエラーハンドラーを登録する方法を示しています。

クリップボードにコピーされました。

const Alexa = require('ask-sdk-core');

const skill = Alexa.SkillBuilders.custom()
  .addRequestHandlers(
    FooHandler,
    BarHandler,
    BazHandler)
  .addRequestInterceptors(
    FooRequestInterceptor,
    BarRequestInterceptor)
  .addResponseInterceptors(
    FooResponseInterceptor,
    BarResponseInterceptor)
  .addErrorHandlers(
    FooErrorHandler,
    BarErrorHandler)
  .create();

クリップボードにコピーされました。

import { SkillBuilders } from 'ask-sdk-core';

const skill = SkillBuilders.custom()
  .addRequestHandlers(
    FooHandler,
    BarHandler,
    BazHandler)
  .addRequestInterceptors(
    FooRequestInterceptor,
    BarRequestInterceptor)
  .addResponseInterceptors(
    FooResponseInterceptor,
    BarResponseInterceptor)
  .addErrorHandlers(
    FooErrorHandler,
    BarErrorHandler)
  .create();