[日本語Alexa] Alexa SDK V2のcanHandleをスッキリ書くためのヘルパー関数

2018.06.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

Alexa SDK のV2の、リクエストハンドラーとエラーハンドラーのインターフェースでは、canHandleというメソッドがあり、SDKから呼び出された際に、そのリクエストを処理するかどうかを返します。

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

canHandleでは、パラメーターとして受け取るHandlerInputオブジェクトから、リクエストのタイプやインテント名、若しくは属性などを確認して、処理対象か否かの判断を行います。

通常のハンドラーでは、リクエストのタイプ及びインテント名で判断されることが多く、下記のような記述が概ね定型句となっています。

const HelloWorldIntentHandler = {
    canHandle(handlerInput) {
        return handlerInput.requestEnvelope.request.type === 'IntentRequest'
            && handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
    },
    handle(handlerInput) {
        // ハンドラーの処理
    }
};

しかし、HandlerInputオブジェクトから、リクエストのタイプやハンドラ名を取得するには、少し階層があり、毎回、これを書くのはちょっと冗長だな感じている方も多いのではないでしょうか。

今回は、この辺の記述を簡潔にするためのヘルパー関数を私なりに検討してみた例を紹介させて下さい。

2 IsMatch

次のメソッドは、インテントタイプやインテント名が、対象かどうかを判断する関数です。

SessionEndedRequest若しくは、LaunchRequestが指定された場合は、リクエストタイプを確認し、それ以外のものが指定された場合は、インテント名として確認するようになっています。 引数は可変で受け取るでの、いくつでも指定する事ができますが、ORで判断されます。(複数のインテント名を持つリクエストは存在しないのでANDで処理する意味がありません)

function isMatch(h, ...intents) {
    return intents.some( intent => {
        if (intent == 'SessionEndedRequest' || intent == 'LaunchRequest') {
            return h.requestEnvelope.request.type == intent;
        }
        if (h.requestEnvelope.request.type == 'IntentRequest') {
            return h.requestEnvelope.request.intent.name === intent
        }
        return false;
    })
}

使い方は、以下のようになります。

const OrderIntentHandler = {
    canHandle(h) {
        return isMatch(h, "OrderIntent");
    },

複数のインテントにも対応していますので、下記のようにも使用できます。

const OrderAndDeliveryIntentHandler = {
    canHandle(h) {
        return isMatch(h, "OrderIntent", "DeliveryIntent");
    },

リクエストタイプが、LaunchRequestSessionEndedRequestの場合は、次のように使用します。

const LaunchRequestHandler = {
    canHandle(h) {
        return isMatch(h, "LaunchRequest");
    },

LaunchRequestタイプとIntentRequestタイプの混在も処理できます。

const LaunchRequestAndOrderIntentHandler = {
    canHandle(h) {
        return isMatch(h, "LaunchRequest", "OrderIntent");
    },

3 checkState

次の関数は、ステートをチェックするものです。 

function checkState(h, state) {
    const attr = h.attributesManager.getSessionAttributes();
    return (attr.STATE == state);
}

なお、Alexa SDK V2では、SDK内にステートの実装は無くなっていますが、V1と同様に、sessionでSTATEという名前でステートを保持した場合という前提で作成されています。

"session": {
        "new": false,
        "sessionId": "amzn1.echo-api.session.xxx",
        "application": {
                "applicationId": "amzn1.ask.skill.xxx"
        },
        "attributes": {
                "STATE": "_ORDER"
        },
        "user": {
                "userId": "amzn1.ask.account.xxx"
        }
},

使い方は、次のとおりです。

const OrderIntentHandler = {
    canHandle(h) {
        return isMatch(h,"OrderIntent") && checkState(h,"_ORDER");
    },

4 最後に

今回は、私の個人的な嗜好で恐縮ですが、canHandleを簡潔に記述するためのヘルパー関数を紹介させて頂きました。

Alexa SDK V2も、徐々に利用範囲が広がって来ていると思うのですが、皆さん、色々と工夫されていることでしょう。もし、妙案がありましたら、是非ご紹介下さい。

5 参考リンク


Request Processing