Request Processing
- Standard Request
- Handler Input
- Request Handlers
- Exception Handlers
- Request and Response Interceptors
Standard Request
Alexa communicates with the skill service via a request-response mechanism using HTTP over SSL/TLS. When a user interacts with an Alexa skill, your service receives a POST request containing a JSON body. The request body contains the parameters necessary for the service to perform its logic and generate a JSON-formatted response. The documentation on JSON structure of the request body can be found here.
Though Python can handle JSON natively as dict
objects, for providing type support, they are deserialized into model objects (ask-sdk-model
package) for skill consumption.
Handler Input
Request Handlers, Request and Response Interceptors, and Exception Handlers are all passed a global HandlerInput
object during invocation. This object exposes various entities useful in request processing, including:
- request_envelope: Contains the entire request body sent to skill, session information and some context information about the input request. Interface details:
ask_sdk_model.request_envelope.RequestEnvelope
- attributes_manager: Provides access to request, session, and persistent attributes. Interface details:
ask_sdk_core.attributes_manager.AttributesManager
- service_client_factory: Constructs service clients capable of calling Alexa APIs. Interface details:
ask_sdk_model.services.service_client_factory.ServiceClientFactory
- response_builder: Contains helper function to build responses. Interface details:
ask_sdk_core.response_helper.ResponseFactory
- context: Provides an optional, context object passed in by the host container. For example, for skills running on AWS Lambda, this is the context object for the AWS Lambda function.
Request Handlers
Request handlers are responsible for handling one or more types of incoming Alexa requests. There are two ways of creating custom request handlers:
- By implementing the
AbstractRequestHandler
class. - By decorating a custom handle function using the Skill Builder
request_handler
decorator.
We recommend that you choose one of the options and use it consistently throughout your skill, for better code structure.
Interface
If you plan on using the AbstractRequestHandler
class, you will need to implement the following methods:
- can_handle:
can_handle
method is called by the SDK to determine if the given handler is capable of processing the incoming request. This function accepts a Handler Input object and expects a boolean to be returned. If the method returns True, then the handler is supposed to handle the request successfully. If it returns False, the handler is not supposed to handle the input request and hence not run to completion. Because of the various attributes inHandlerInput
object, you can write any condition to let SDK know whether the request can be handled gracefully or not. - handle:
handle
method is called by the SDK when invoking the request handler. This function contains the handler's request processing logic, accepts Handler Input and returns aResponse
object.
class AbstractRequestHandler(object):
@abstractmethod
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
pass
@abstractmethod
def handle(self, handler_input):
# type: (HandlerInput) -> Response
pass
The request_handler
decorator from SkillBuilder class is a custom wrapper on top of the AbstractRequestHandler
class and provides the same functionality to any custom decorated function. However, there are couple of things to take into consideration, before using the decorator:
- The decorator expects a
can_handle_func
parameter. This is similar to thecan_handle
method inAbstractRequestHandler
. The value passed should be a function that accepts a Handler Input object and returns aboolean
value. - The decorated function should accept only one parameter, which is the Handler Input object and may return a
Response
object.
class SkillBuilder(object):
....
def request_handler(self, can_handle_func):
def wrapper(handle_func):
# wrap the can_handle and handle into a class
# add the class into request handlers list
....
return wrapper
Code Sample
The following example shows a request handler class that can handle the 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 = "Hello World";
return handler_input.response_builder.speak(speech_text).set_card(
SimpleCard("Hello World", speech_text)).response
The can_handle
function detects if the incoming request is an IntentRequest
and returns true if the intent name is HelloWorldIntent
. The handle
function generates and returns a basic "Hello World" response.
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 = "Hello World!"
return handler_input.response_builder.speak(speech_text).set_card(
SimpleCard("Hello World", speech_text)).response
The is_intent_name
function accepts a string
parameter and returns an anonymous function which accepts a HandlerInput
as input parameter and checks if the incoming request in HandlerInput
is an IntentRequest
and returns if the intent name is the passed in string
, which is HelloWorldIntent
in this example. The handle
function generates and returns a basic "Hello World" response.
Registering and Processing the Request Handlers
The SDK calls the can_handle
function on its request handlers in the order in which they were provided to the Skill
builder.
If you are following the AbstractRequestHandler
class approach, then you can register the request handlers in the following way:
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# Implement FooHandler, BarHandler, BazHandler classes
sb.add_request_handler(FooHandler())
sb.add_request_handler(BarHandler())
sb.add_request_handler(BazHandler())
If you are following the request_handler
decorator approach, then there is no need to explicitly register the handler functions, since they are already decorated using a skill builder instance.
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# decorate foo_handler, bar_handler, baz_handler functions
1.
FooHandler
class / foo_handler
function2.
BarHandler
class / bar_handler
function3.
BazHandler
class / baz_handler
functionThe SDK always chooses the first handler that is capable of handling a given request. In this example, if both
FooHandler
class /foo_handler
function and BarHandler
class /bar_handler
function are capable of handling a particular request, FooHandler
class /foo_handler
function is always invoked. Keep this in mind when designing and registering request handlers.Exception Handlers
Exception handlers are similar to request handlers, but are instead responsible for handling one or more types of exceptions. They are invoked by the SDK when an unhandled exception is thrown during the course of request processing.
In addition to the Handler Input object, the handler also has access to the exception raised during handling the input request, thus making it easier for the handler to figure out how to handle the corresponding exception.
Similar to Request Handlers, exception handlers can be implemented in two ways:
- By implementing the
AbstractExceptionHandler
class. - By decorating a custom exception handling function using the Skill Builder
exception_handler
decorator.
We recommend that you choose one of the options and use it consistently throughout your skill, for better code structure.
Interface
If you plan on using the AbstractExceptionHandler
class, you will need to implement the following methods:
- can_handle:
can_handle
method, which is called by the SDK to determine if the given handler is capable of handling the exception. This function returns True if the handler can handle the exception, or False if not. ReturnTrue
in all cases to create a catch-all handler. - handle:
handle
method, which is called by the SDK when invoking the exception handler. This function contains all exception handling logic, and returns aResponse
object.
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
The exception_handler
decorator from SkillBuilder class is a custom wrapper on top of the AbstractExceptionHandler
class and provides the same functionality to any custom decorated function. However, there are couple of things to take into consideration, before using the decorator:
- The decorator expects a
can_handle_func
parameter. This is similar to thecan_handle
method inAbstractExceptionHandler
. The value passed should be a function that accepts a Handler Input object, anException
instance and returns aboolean
value. - The decorated function should accept only two parameters, the Handler Input object and
Exception
object. It may return aResponse
object.
class SkillBuilder(object):
....
def exception_handler(self, can_handle_func):
def wrapper(handle_func):
# wrap the can_handle and handle into a class
# add the class into exception handlers list
....
return wrapper
Code Sample
The following example shows an exception handler that can handle any exception with name that contains "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 = "Sorry, I am unable to figure out what to do. Try again later!!"
return handler_input.response_builder.speak(speech_text).response
The handler's can_handle
method returns True if the incoming exception has a name that starts with "AskSdk". The handle
method returns a graceful exception response to the user.
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 = "Sorry, I am unable to figure out what to do. Try again later!!"
return handler_input.response_builder.speak(speech_text).response
Registering and Processing the Exception Handlers
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# Implement FooExceptionHandler, BarExceptionHandler, BazExceptionHandler classes
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()
# decorate foo_exception_handler, bar_exception_handler, baz_exception_handler functions
Request and Response Interceptors
The SDK supports Global Request and Response Interceptors that run before and after the matching RequestHandler
, respectively.
Request Interceptors
The Global Request Interceptor accepts a Handler Input object and processes it, before processing any of the registered request handlers. Similar to Request Handlers, custom request interceptors can be implemented in two ways:
- By implementing the
AbstractRequestInterceptor
class. - By decorating a custom process function using the Skill Builder
global_request_interceptor
decorator.
We recommend that you choose one of the options and use it consistently throughout your skill, for better code structure.
Interface
The AbstractRequestInterceptor
class usage needs you to implement the process
method. This method takes a Handler Input instance and doesn't return anything.
class AbstractRequestInterceptor(object):
@abstractmethod
def process(self, handler_input):
# type: (HandlerInput) -None
pass
The global_request_interceptor
decorator from SkillBuilder class is a custom wrapper on top of the AbstractRequestInterceptor
class and provides the same functionality to any custom decorated function. However, there are couple of things to take into consideration, before using the decorator:
- The decorator should be invoked as a function rather than as a function name, since it requires the skill builder instance, to register the interceptor.
- The decorated function should accept only one parameter, which is the Handler Input object and the return value from the function is not captured.
class SkillBuilder(object):
....
def global_request_interceptor(self):
def wrapper(process_func):
# wrap the process_func into a class
# add the class into request interceptors list
....
return wrapper
Code Sample
The following example shows a request interceptor class that can print the request received by Alexa service, in AWS CloudWatch logs, before handling it.
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))
Registering and Processing the Request Interceptors
Request interceptors are invoked immediately before execution of the request handler for an incoming request. Request attributes in Handler Input's Attribute Manager
provide a way for request interceptors to pass data and entities on to other request interceptors and request handlers.
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# Implement FooInterceptor, BarInterceptor, BazInterceptor classes
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()
# decorate foo_interceptor, bar_interceptor, baz_interceptor functions
1.
FooInterceptor
class / foo_interceptor
function2.
BarInterceptor
class / bar_interceptor
function3.
BazInterceptor
class / baz_interceptor
functionResponse Interceptors
The Global Response Interceptor accepts a Handler Input object, a Response and processes them, after executing the supported request handler. Similar to Request Interceptors, custom response interceptors can be implemented in two ways:
- By implementing the
AbstractResponseInterceptor
class. - By decorating a custom process function using the Skill Builder
global_response_interceptor
decorator.
We recommend that you choose one of the options and use it consistently throughout your skill, for better code structure.
Interface
The AbstractResponseInterceptor
class usage needs you to implement the process
method. This method takes a Handler Input instance, a Response
object that is returned by the request handler. The method doesn't return anything.
class AbstractResponseInterceptor(object):
@abstractmethod
def process(self, handler_input, response):
# type: (HandlerInput, Response) -None
pass
The global_response_interceptor
decorator from SkillBuilder class is a custom wrapper on top of the AbstractResponseInterceptor
class and provides the same functionality to any custom decorated function. However, there are couple of things to take into consideration, before using the decorator:
- The decorator should be invoked as a function rather than as a function name, since it requires the skill builder instance, to register the interceptor.
- The decorated function should accept two parameters, which are the Handler Input object and
Response
object respectively. The return value from the function is not captured.
class SkillBuilder(object):
....
def global_response_interceptor(self):
def wrapper(process_func):
# wrap the process_func into a class
# add the class into response interceptors list
....
return wrapper
Code Sample
The following example shows a response interceptor class that can print the response received from successfully handling the request, in AWS CloudWatch logs, before returning it to the Alexa service.
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))
Registering and Processing the Response Interceptors
Response interceptors are invoked immediately after execution of the request handler for an incoming request.
from ask_sdk_core.skill_builder import SkillBuilder
sb = SkillBuilder()
# Implement FooInterceptor, BarInterceptor, BazInterceptor classes
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()
# decorate foo_interceptor, bar_interceptor, baz_interceptor functions
Last updated: Nov 28, 2023