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
AbstractRequestHandlerclass. - By decorating a custom handle function using the Skill Builder
request_handlerdecorator.
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_handlemethod 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 inHandlerInputobject, you can write any condition to let SDK know whether the request can be handled gracefully or not. - handle:
handlemethod is called by the SDK when invoking the request handler. This function contains the handler's request processing logic, accepts Handler Input and returns aResponseobject.
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_funcparameter. This is similar to thecan_handlemethod inAbstractRequestHandler. The value passed should be a function that accepts a Handler Input object and returns abooleanvalue. - The decorated function should accept only one parameter, which is the Handler Input object and may return a
Responseobject.
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
AbstractExceptionHandlerclass. - By decorating a custom exception handling function using the Skill Builder
exception_handlerdecorator.
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_handlemethod, 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. ReturnTruein all cases to create a catch-all handler. - handle:
handlemethod, which is called by the SDK when invoking the exception handler. This function contains all exception handling logic, and returns aResponseobject.
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_funcparameter. This is similar to thecan_handlemethod inAbstractExceptionHandler. The value passed should be a function that accepts a Handler Input object, anExceptioninstance and returns abooleanvalue. - The decorated function should accept only two parameters, the Handler Input object and
Exceptionobject. It may return aResponseobject.
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
AbstractRequestInterceptorclass. - By decorating a custom process function using the Skill Builder
global_request_interceptordecorator.
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
AbstractResponseInterceptorclass. - By decorating a custom process function using the Skill Builder
global_response_interceptordecorator.
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
Responseobject 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