リクエスト処理
標準のリクエスト
作成したスキルサービスとAlexaとの通信は、SSL/TLSを利用してHTTPを使用するリクエスト-応答メカニズムで行います。ユーザーがAlexaスキルと対話するとき、作成したサービスは、JSON本文を含むPOSTリクエストを受け取ります。このリクエスト本文には、サービスがロジックを実行してJSON形式の応答を生成するために必要なパラメーターが含まれています。リクエスト本文のJSON構造についてのドキュメントは、こちらを参照してください。
PythonはJSONをdict
オブジェクトとしてネイティブに処理できますが、型をサポートするため、スキルで利用するにはモデルオブジェクト(ask-sdk-model
パッケージ)に逆シリアル化されます。
ハンドラー入力
リクエストハンドラー、リクエストと応答のインターセプター、例外ハンドラーにはすべて、呼び出し時に共通のHandlerInput
オブジェクトが渡されます。このオブジェクトには、リクエスト処理に有効な各種エンティティが含まれます。以下はその例です。
- request_envelope: スキルに送信されるリクエスト本文全体、セッション情報、入力リクエストに関するコンテキスト情報が含まれます。インターフェース情報:
ask_sdk_model.request_envelope.RequestEnvelope
- attributes_manager: リクエスト、セッション、永続アトリビュートへのアクセスを提供します。インターフェース情報:
ask_sdk_core.attributes_manager.AttributesManager
- service_client_factory: Alexa APIの呼び出しが可能なサービスクライアントを構築します。インターフェース情報:
ask_sdk_model.services.service_client_factory.ServiceClientFactory
- response_builder: 応答を作成するヘルパー関数を含みます。インターフェース情報:
ask_sdk_core.response_helper.ResponseFactory
- context: ホストコンテナが渡すオプションのcontextオブジェクトを提供します。たとえば、AWS Lambdaで実行されるスキルの場合は、AWS Lambda関数のcontextオブジェクトになります。
リクエストハンドラー
リクエストハンドラーは、受信するさまざまなタイプのAlexaリクエストの処理を担当します。カスタムリクエストハンドラーを作成する方法は2つあります。
AbstractRequestHandler
クラスを実装する。- スキルビルダーの
request_handler
デコレーターを使用してカスタムハンドル関数をデコレートする。
コード構造を良好に保つために、いずれかのオプションを選択し、スキル全体で常に使用することを強くお勧めします。
インターフェース
AbstractRequestHandler
クラスの使用を予定している場合は、次のメソッドを実装する必要があります。
- can_handle:
can_handle
メソッドは、SDKによって呼び出され、指定されたハンドラーが受け取ったリクエストを処理できるかどうかを判断します。この関数はハンドラー入力オブジェクトを受け付け、ブール型を返すように想定されています。メソッドがTrueを返せば、ハンドラーによってリクエストが正常に処理されたと考えられます。Falseを返す場合、ハンドラーが入力リクエストを処理できず、したがって実行されず完了もしなかったと考えられます。HandlerInput
オブジェクトにはさまざまなアトリビュートがあるため、リクエストを正常に処理できるかどうかをSDKが判別するための任意の条件を作成できます。 - handle:
handle
メソッドは、リクエストハンドラーを呼び出すときにSDKによって呼び出されます。この関数には、ハンドラーのリクエスト処理ロジックが含まれており、ハンドラー入力を受け取り、応答
オブジェクトを返します。
class AbstractRequestHandler(object):
@abstractmethod
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
pass
@abstractmethod
def handle(self, handler_input):
# type: (HandlerInput) -> Response
pass
SkillBuilderクラスのrequest_handler
デコレーターは、AbstractRequestHandler
クラスに搭載されたカスタムラッパーであり、カスタムでデコレートされた任意の関数と同じ機能を提供します。ただし、デコレーターを使用するには考慮事項が2つあります。
- デコレーターは
can_handle_func
パラメーターを取ります。これはAbstractRequestHandler
のcan_handle
メソッドに似たものです。渡される値はハンドラー入力オブジェクトを受け付け、ブール型
値を返す関数である必要があります。 - デコレートされた関数が受け付けるパラメーターはハンドラー入力1つのみであり、
応答
オブジェクトを返します。
class SkillBuilder(object):
....
def request_handler(self, can_handle_func):
def wrapper(handle_func):
# can_handleとhandleをクラスにラップします
# クラスをリクエストハンドラーリストに追加します
....
return wrapper
サンプルコード
以下は、HelloWorldIntent
を呼び出すことができるリクエストハンドラークラスの例です。
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.utils import is_intent_name
from ask_sdk_model.ui import SimpleCard
class HelloWorldIntentHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
return is_intent_name("HelloWorldIntent")(handler_input)
def handle(self, handler_input):
speech_text = "こんにちは";
return handler_input.response_builder.speak(speech_text).set_card(
SimpleCard("ハローワールド", speech_text)).response
can_handle
関数は受け取るリクエストがIntentRequest
かどうかを検出し、インテント名がHelloWorldIntent
の場合にtrueを返します。handle
関数は、基本的な「こんにちは」という応答を生成して返します。
from ask_sdk_core.utils import is_intent_name
from ask_sdk_model.ui import SimpleCard
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
@sb.request_handler(can_handle_func = is_intent_name("HelloWorldIntent"))
def hello_world_intent_handler(handler_input):
speech_text = "こんにちは"
return handler_input.response_builder.speak(speech_text).set_card(
SimpleCard("ハローワールド", speech_text)).response
is_intent_name
関数はstring
パラメーターを受け取り無名関数を返します。この無名関数は、HandlerInput
を入力パラメーターとして受け取って、HandlerInput
の受信リクエストがIntentRequest
であるかを確認し、インテント名がstring
に渡されているものであればそれを返します。この例ではHelloWorldIntent
です。handle
関数は、基本的な「こんにちは」という応答を生成して返します。
リクエストハンドラーの登録と処理
SDKは、リクエストハンドラーで、スキル
ビルダーに指定された順序でcan_handle
関数を呼び出します。
AbstractRequestHandler
クラスを使用する方法に従っている場合、次の方法でリクエストハンドラーを登録できます。
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# FooHandler、BarHandler、BazHandlerクラスを実装します
sb.add_request_handler(FooHandler())
sb.add_request_handler(BarHandler())
sb.add_request_handler(BazHandler())
request_handler
デコレーターを使用する方法に従っている場合、ハンドラー関数を明示的に登録する必要はありません。スキルビルダーインスタンスを使用して既にデコレートされています。
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# foo_handler、bar_handler、baz_handler関数をデコレートします
1.FooHandler
クラス/
foo_handler関数
2.BarHandler
クラス/
bar_handler関数
3.BazHandler
クラス/
baz_handler関数
SDKは、指定されたリクエストを処理できる最初のハンドラーを常に選択します。この例では、
FooHandler
クラス/foo_handler
関数およびBarHandler
クラス/bar_handler
関数のどちらも指定のリクエストを処理できる場合、FooHandler
クラス/foo_handler
関数が常に呼び出されます。リクエストハンドラーのデザインや登録を行う際には、この点を考慮に入れてください。例外ハンドラー
例外ハンドラーはリクエストハンドラーに似ていますが、リクエストではなく1つまたは複数のタイプの例外を処理します。リクエストの処理中に未処理の例外がスローされると、SDKが例外ハンドラーを呼び出します。
ハンドラーはハンドラー入力オブジェクトに加えて、入力リクエストの処理中に発生した例外にもアクセスできます。そのため、ハンドラーが該当する例外の処理方法を判別しやすくなります。
リクエストハンドラーと同様に、例外ハンドラーも2とおりの方法で実装できます。
AbstractExceptionHandler
クラスを実装する。- スキルビルダーの
exception_handler
デコレーターを使用してカスタム例外ハンドル関数をデコレートする。
コード構造を良好に保つために、いずれかのオプションを選択し、スキル全体で常に使用することを強くお勧めします。
インターフェース
AbstractExceptionHandler
クラスの使用を予定している場合は、次のメソッドを実装する必要があります。
- can_handle:
can_handle
メソッドはSDKによって呼び出され、指定されたハンドラーが例外を処理できるかどうかを判断します。ハンドラーが例外を処理できる場合はTrue、できない場合はFalseを返します。catch-allハンドラーを作成する場合は常にTrue
を返します。 - handle:
handle
メソッドは例外ハンドラーを呼び出すときにSDKによって呼び出されます。この関数には、例外処理ロジックがすべて含まれ、応答
オブジェクトを返します。
class AbstractExceptionHandler(object):
@abstractmethod
def can_handle(self, handler_input, exception):
# type: (HandlerInput, Exception) -bool
pass
@abstractmethod
def handle(self, handler_input, exception):
# type: (HandlerInput, Exception) -Response
pass
SkillBuilderクラスのexception_handler
デコレーターは、AbstractExceptionHandler
クラスに搭載されたカスタムラッパーであり、カスタムでデコレートされた任意の関数と同じ機能を提供します。ただし、デコレーターを使用するには以下の2点を考慮してください。
- デコレーターは
can_handle_func
パラメーターを取ります。これはAbstractExceptionHandler
のcan_handle
メソッドに似たものです。渡される値はハンドラー入力オブジェクトを例外
インスタンスとして受け付け、ブール型
値を返す関数である必要があります。 - デコレートされた関数が受け付けるパラメーターはハンドラー入力オブジェクトおよび
例外
オブジェクトの2つのみです。応答
オブジェクトが返されます。
class SkillBuilder(object):
....
def exception_handler(self, can_handle_func):
def wrapper(handle_func):
# can_handleとhandleをクラスにラップします
# クラスを例外ハンドラーリストに追加します
....
return wrapper
サンプルコード
以下は、名前に「AskSdk」が含まれる例外をすべて処理する例外ハンドラーの例です。
class AskExceptionHandler(AbstractExceptionHandler):
def can_handle(self, handler_input, exception):
return 'AskSdk' in exception.__class__.__name__
def handle(self, handler_input, exception):
speech_text = "すみません、何をしたらいいのかわかりません。後でもう一度お試しください。"
return handler_input.response_builder.speak(speech_text).response
ハンドラーのcan_handle
メソッドは、受け取る例外の名前が「AskSdk」で始まる場合にTrueを返します。handle
メソッドは、ユーザーに正常な例外応答を返します。
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
@sb.exception_handler(can_handle_func = lambda i, e: 'AskSdk' in e.__class__.__name__)
def ask_exception_intent_handler(handler_input, exception):
speech_text = "すみません、何をしたらいいのかわかりません。後でもう一度お試しください。"
return handler_input.response_builder.speak(speech_text).response
例外ハンドラーの登録と処理
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# FooExceptionHandler、BarExceptionHandler、BazExceptionHandlerクラスを実装します
sb.add_exception_handler(FooExceptionHandler())
sb.add_exception_handler(BarExceptionHandler())
sb.add_exception_handler(BazExceptionHandler())
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# foo_exception_handler、bar_exception_handler、baz_exception_handler関数をデコレートします
リクエストと応答のインターセプター
SDKは、一致するRequestHandler
の実行前と実行後に実行するリクエストと応答のグローバルインターセプターをサポートします。
リクエストインターセプター
グローバルリクエストインターセプターは、登録されたリクエストハンドラーの処理前に、ハンドラー入力オブジェクトを受け付けて処理します。リクエストハンドラーと同様に、カスタムリクエストインターセプターも2とおりの方法で実装できます。
AbstractRequestInterceptor
クラスを実装する。- スキルビルダーの
global_request_interceptor
デコレーターを使用してカスタム処理関数をデコレートする。
コード構造を良好に保つために、いずれかのオプションを選択し、スキル全体で常に使用することを強くお勧めします。
インターフェース
AbstractRequestInterceptor
クラスを使用するには、処理
メソッドを実装する必要があります。このメソッドはハンドラー入力インスタンスを取得し、何も返しません。
class AbstractRequestInterceptor(object):
@abstractmethod
def process(self, handler_input):
# type: (HandlerInput) -None
pass
SkillBuilderクラスのglobal_request_interceptor
デコレーターは、AbstractRequestInterceptor
クラスに搭載されたカスタムラッパーであり、カスタムでデコレートされた任意の関数と同じ機能を提供します。ただし、デコレーターを使用するには以下の2点を考慮してください。
- デコレーターはスキルビルダーインスタンスを必要とするため、インターセプターを登録するには、関数名としてではなく関数として呼び出される必要があります。
- デコレートされた関数が受け付けるパラメーターはハンドラー入力オブジェクト1つのみであり、関数からの戻り値はキャプチャーされません。
class SkillBuilder(object):
....
def global_request_interceptor(self):
def wrapper(process_func):
# process_funcをクラスにラップします
# クラスをリクエストインターセプターリストに追加します
....
return wrapper
サンプルコード
以下は、Alexaサービスが受け取ったリクエストを、処理の前にAWS CloudWatchログに書き込むリクエストインターセプタークラスの例です。
from ask_sdk_core.dispatch_components import AbstractRequestInterceptor
class LoggingRequestInterceptor(AbstractRequestInterceptor):
def process(self, handler_input):
print("Request received: {}".format(handler_input.request_envelope.request))
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
@sb.global_request_interceptor()
def request_logger(handler_input):
print("Request received: {}".format(handler_input.request_envelope.request))
リクエストインターセプターの登録と処理
リクエストのインターセプターは、受け取るリクエストのリクエストハンドラーが実行される直前に呼び出されます。ハンドラー入力のアトリビュートマネージャー
内のリクエストアトリビュートは、リクエストインターセプターが他のリクエストインターセプターやリクエストハンドラーにデータやエンティティを渡す方法を提供します。
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# FooInterceptor、BarInterceptor、BazInterceptorクラスを実装します
sb.add_global_request_interceptor(FooInterceptor())
sb.add_global_request_interceptor(BarInterceptor())
sb.add_global_request_interceptor(BazInterceptor())
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# foo_interceptor、bar_interceptor、baz_interceptor関数をデコレートします
1.FooInterceptor
クラス/
foo_interceptor関数
2.BarInterceptor
クラス/
bar_interceptor関数
3.BazInterceptor
クラス/
baz_interceptor関数
応答インターセプター
グローバル応答インターセプターは、サポートされるリクエストハンドラーの処理後に、ハンドラー入力オブジェクト、つまり応答を受け付けて処理します。リクエストインターセプターと同様に、カスタム応答インターセプターも2とおりの方法で実装できます。
AbstractResponseInterceptor
クラスを実装する。- スキルビルダーの
global_response_interceptor
デコレーターを使用してカスタム処理関数をデコレートする。
コード構造を良好に保つために、いずれかのオプションを選択し、スキル全体で常に使用することを強くお勧めします。
インターフェース
AbstractResponseInterceptor
クラスを使用するには、処理
メソッドを実装する必要があります。このメソッドはハンドラー入力インスタンスの、先に実行されたリクエストハンドラーから返された応答
オブジェクトを取ります。このメソッドから返されるものはありません。
class AbstractResponseInterceptor(object):
@abstractmethod
def process(self, handler_input, response):
# type: (HandlerInput, Response) -None
pass
SkillBuilderクラスのglobal_response_interceptor
デコレーターは、AbstractResponseInterceptor
クラスに搭載されたカスタムラッパーであり、カスタムでデコレートされた任意の関数と同じ機能を提供します。ただし、デコレーターを使用するには以下の2点を考慮してください。
- デコレーターはスキルビルダーインスタンスを必要とするため、インターセプターを登録するには、関数名としてではなく関数として呼び出される必要があります。
- デコレートされた関数は2つのパラメーターを受け付けます。それぞれハンドラー入力オブジェクトおよび
応答
オブジェクトです。この関数から返される値はキャプチャーされません。
class SkillBuilder(object):
....
def global_response_interceptor(self):
def wrapper(process_func):
# process_funcをクラスにラップします
# クラスを応答インターセプターリストに追加します
....
return wrapper
サンプルコード
以下は、正常に処理されたリクエストから受け取った応答を、Alexaサービスにその応答が返される前にAWS CloudWatchログに書き込む応答インターセプタークラスの例です。
from ask_sdk_core.dispatch_components import AbstractResponseInterceptor
class LoggingResponseInterceptor(AbstractResponseInterceptor):
def process(handler_input, response):
print("Response generated: {}".format(response))
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
@sb.global_response_interceptor()
def response_logger(handler_input, response):
print("Response generated: {}".format(response))
応答インターセプターの登録と処理
応答インターセプターは、受け取るリクエストのリクエストハンドラーが実行された直後に呼び出されます。
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# FooInterceptor、BarInterceptor、BazInterceptorクラスを実装します
sb.add_global_response_interceptor(FooInterceptor())
sb.add_global_response_interceptor(BarInterceptor())
sb.add_global_response_interceptor(BazInterceptor())
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# foo_interceptor、bar_interceptor、baz_interceptor関数をデコレートします