リクエスト処理



リクエスト処理

リクエストハンドラー

リクエストハンドラーは、受け取った1つ以上のタイプのリクエストを処理します。

リクエストハンドラーを作成するには、RequestHandlerインターフェースまたは型付けされたリクエストハンドラーインターフェースを実装します。どちらも次の2つのメソッドで構成されます。

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

汎用のリクエストハンドラー

汎用のRequestHandlerインターフェースは、複数のリクエストタイプを処理する場合に使用でき、さまざまなリクエストタイプで類似のコードパスがある場合に役立ちます。

以下は、受信したSkillEnabledRequestまたはSkillDisabledRequestを処理するように設定されたリクエストハンドラーの例です。

public class SkillEventsHandler implements RequestHandler {
    @Override
    public boolean canHandle(HandlerInput input) {
        return input.getRequest() instanceof SkillEnabledRequest
                || input.getRequest() instanceof SkillDisabledRequest;
    }

    @Override
    public Optional<Response> handle(HandlerInput input) {
        logger.info("スキルイベントが受信されました");

        if (input.getRequest() instanceof SkillEnabledRequest) {
            SkillEnabledRequest request = (SkillEnabledRequest) input.getRequest();
            logger.info("ユーザーが{}にスキルを有効にしました", request.getEventCreationTime());
        }

        if (input.getRequest() instanceof SkillDisabledRequest) {
            SkillDisabledRequest request = (SkillDisabledRequest) input.getRequest();
            logger.info("ユーザーが{}にスキルを無効にしました", request.getEventCreationTime());
        }
    }
}

型付けされたリクエストハンドラー

SDKがサポートする各リクエストタイプ(IntentRequest、LaunchRequest、SkillEnabledRequestなど)に型付けされたリクエストハンドラーインターフェースを利用でき、特定のリクエストタイプのハンドラーを作成するための型安全な方法が提供されます。汎用のRequestHandlerインターフェースを使用する場合は、型を確認し、特定のリクエストの型に対して機能するようにキャストする必要があります。型付けされたハンドラーではその必要はなく、ハンドラーが型の確認処理を行います。たとえばLaunchRequestHandlerインターフェースを実装するハンドラーは、受信リクエストがLaunchRequestの場合のみ呼び出されます。

現在利用可能な型固有のリクエストハンドラーのリストは、こちらを参照してください。

以下は、HelloWorldIntentを処理するよう設定されたリクエストハンドラーの例です。このように、インテントリクエストを処理する場合、ハンドラーはIntentRequestHandlerインターフェースを実装します。

public class HelloWorldIntentHandler implements IntentRequestHandler {
    @Override
    public boolean canHandle(HandlerInput input, IntentRequest intentRequest) {
        return intentRequest.getIntent().getName().equals("HelloWorldIntent");
    }

    @Override
    public Optional<Response> handle(HandlerInput input, IntentRequest intentRequest) {
        String speechText = "こんにちは";

        Intent intent = intentRequest.getIntent();
        String intentName = intent.getName();

        return input.getResponseBuilder()
                .withSpeech(speechText)
                .withSimpleCard(intentName, speechText)
                .build();
    }
}

このタイプのハンドラーは、受信リクエストがIntentRequestである場合のみ呼び出されます。ハンドラーのcanHandleメソッドは、リクエストのインテント名を確認し、インテント名がHelloWorldIntentの場合はtrueを返すよう設定されています。handleメソッドで基本の「こんにちは」という応答が生成され、返されます。canHandleの条件を変更すると、たとえばインテントのスロット値を検査することでハンドラーをさらにきめ細かくしたり、すべてのIntentRequestに対してtrueを返してハンドラーをより汎用的にしたりすることができます。

CanHandle述部

SDKには、インテント名、スロット値、アトリビュートなど共通の条件を簡単に評価できる、プリビルドされた一連のcanHandle述部が含まれています。これにより、複雑なcanHandle条件を持つロジックの作成が、より簡単にシンプルに作成できます。SDKで提供される利用可能な述部のリストは、こちらを参照してください。

たとえば、上記のHelloWorldインテントのサンプルハンドラーは、述部を使用してCanHandle条件をシンプルにできます。

@Override
public boolean canHandle(HandlerInput input, IntentRequest intentRequest) {
    return input.matches(Predicates.intentName("HelloWorldIntent"));
}

同様に、SkillEnabledRequest用またはSkillDisabledRequest用のハンドラーを示す汎用RequestHandlerの例は、次のようになります。

@Override
public boolean canHandle(HandlerInput input) {
    return input.matches(Predicates.requestType(SkillEnabledRequest.class)
        .or(Predicates.requestType(SkillDisabledRequest.class)));
}

ハンドラーの処理順序

SDKは、リクエストハンドラーで、スキルビルダーに提供した順序でcanHandleメソッドを呼び出します。同じリクエストタイプ用の複数のハンドラー(IntentRequestHandlerを実装する複数のハンドラーなど)を含め、スキルには必要な数のリクエストハンドラーを実装することができます。この場合、SDKは登録された順序でこれらのハンドラーにアクセスし、canHandleメソッドで最初にtrueを返したハンドラーを利用します。

return Skills.standard()
    .addHandlers(new FooHandler(), new BarHandler(), new BazHandler())
    .build();

この例では、SDKが以下の順序でリクエストハンドラーを呼び出します。

  1. FooHandler
  2. BarHandler
  3. BazHandler

SDKは、指定されたリクエストを処理できる最初のハンドラーを常に選択します。この例では、FooHandlerBarHandlerの両方が特定のリクエストを処理できる場合、常にFooHandlerが呼び出されます。リクエストハンドラーのデザインや登録を行う際には、この点を考慮に入れてください。

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

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

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

public class PersistenceSavingResponseInterceptor implements ResponseInterceptor {
    @Override
    public void process(HandlerInput input, Optional<Response> output) {
        input.getAttributesManager().savePersistentAttributes();
    }
}

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

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

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

return Skills.standard()
    .addHandlers(new FooHandler(), new BarHandler(), new BazHandler())
    .addRequestInterceptors(new FooRequestInterceptor())
    .addResponseInterceptors(new BarResponseInterceptor())
    .build();

例外ハンドラー

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

すべての例外ハンドラーは、ExceptionHandlerインターフェースを実装する必要があります。このインターフェースは以下の2つのメソッドで構成されます。

  • canHandleは、SDKによって呼び出され、指定されたハンドラーが例外を処理できるかどうかを判断します。ハンドラーが例外を処理できる場合はtrue、できない場合はfalseを返します。catch-allハンドラーは常にtrueを返すだけで簡単に導入できます。
  • handleは、例外ハンドラーを呼び出すときにSDKによって呼び出されます。​このメソッドには、例外処理ロジックがすべて含まれ、オプションでResponseを含む場合がある出力を返します。

以下は、AskSdkExceptionタイプの例外を処理するよう設定された例外ハンドラーの例です。

public class MyExecptionHandler implements ExceptionHandler {
    @Override
    public boolean canHandle(HandlerInput input, Throwable throwable) {
        return throwable instanceof AskSdkException;
    }

    @Override
    public HandlerOutput handle(HandlerInput input, Throwable throwable) {
        return input.getResponseBuilder()
                    .withSpeech("リクエストの処理中にエラーが発生しました。後でもう一度お試しください。")
                    .build();
    }
}

ハンドラーのcanHandleメソッドは、受け取る例外がAskSdkExceptionのインスタンスである場合にtrueを返します。handleメソッドは、ユーザーに正常なエラー応答を返します。

例外ハンドラーはリクエストハンドラーと同様に実行され、SDKはSkillで指定した順序でハンドラーにアクセスします。

ハンドラー入力

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

  • RequestEnvelope: 受信するRequestと他のコンテキストが含まれます。
  • AttributesManager: リクエスト、セッション、永続アトリビュートへのアクセスを提供します。
  • ServiceClientFactory: Alexa APIの呼び出しが可能なサービスクライアントを構築します。
  • ResponseBuilder: 応答を作成するのを支援します。
  • Context: ホストコンテナが渡すオプションのcontextオブジェクトを提供します。たとえば、AWS Lambdaで実行されるスキルの場合は、AWS Lambda関数のcontextオブジェクトになります。