Deploy a Sample Custom Skill as a Web Service

The Java samples provided with the Alexa Skills Kit can be hosted as web services. This document provides the steps this scenario – both running as sample on the command line, as well as deploying a sample as a web service with AWS Elastic Beanstalk, a service offering by Amazon Web Services.

Note that it is generally faster and easier to deploy and test the samples as AWS Lambda functions on AWS Lambda (a service offering by Amazon Web Services). You can use Lambda with either the Java or Node.js samples. See Deploying a Sample Custom Skill to AWS Lambda for detailed steps.

The samples are available in GitHub repositories. For details about getting the samples and the specific samples included, see Using the Alexa Skills Kit Samples (Custom Skills).

System Requirements

Setting up and running the samples requires the following:

Additional requirements depend on how you want to test the samples. See the relevant sections below:

Building and Running a Sample from the Command Line

These steps show how to build and run the Hello World sample from the command line on the Linux platform. Doing this lets you send HTTP requests using a command line tool such as cURL.

The Launcher class provided in the src/main/java folder starts a Jetty server that can host a Speechlet for one of the samples, such as the HelloWorldSpeechlet. This is a convenient way to run the samples from the command line.

Note that running the sample in this way does not normally make it available through an Internet-accessible endpoint, so you cannot test your code with an actual device in this way. Testing on the command line can still be useful for understanding the requests and responses used by the web service for an Alexa skill. For an example of deploying the sample to the cloud instead, see Setting up Hello World on Elastic Beanstalk, below.

Running Hello World from the command line requires these tools, in addition to the Java requirements noted earlier:

To run a sample from the command line, do the following:

  1. Download or clone the amzn/alexa-skills-kit-java GitHub repository.
  2. Create a self-signed certificate, as described in Testing a Custom Skill.
  3. Use the private key and certificate to set up a Java KeyStore and include information about the KeyStore in the pom.xml file for the samples. See Setting Up an SSL/TLS Java KeyStore.
  4. Build and run the sample using Maven, then use cURL to send requests to the sample and note the responses. See Running the Sample from the Command Line.

In these instructions, <alexa-skills-kit-folder> is the folder you cloned from the GitHub repository.

Setting Up an SSL/TLS Java KeyStore

Follow these steps to create a Java KeyStore and to configure the Hello World sample to build using that KeyStore:

  1. Create a private key and self-signed certificate. See the detailed instructions in Testing a Custom Skill.
  2. Use the following openssl command to create a PKCS #12 archive file from your private key and certificate.Replace the private-key.pem and certificate.pem values shown here with the filenames for your key and certificate. Specify a password for the archive when prompted.

    openssl pkcs12 \
         -keypbe PBE-SHA1-3DES \
         -certpbe PBE-SHA1-3DES \
         -inkey private-key.pem \
         -in certificate.pem -export \
         -out keystore.pkcs12 \
    

    Indented para…

  3. Use the following keytool command to import the PKCS #12 file into a Java KeyStore, specifying a password for both the destination KeyStore and source PKCS #12 archive:

    $JAVA_HOME/bin/keytool \
         -importkeystore \
         -destkeystore java-keystore.jks \
         -srckeystore keystore.pkcs12 \
         -srcstoretype PKCS12 \
    
  4. Edit the pom.xml file in <alexa-skills-kit-folder>/samples to provide settings for the javax.net.ssl.keyStore and javax.net.ssl.keyStorePassword system properties. Set the values to the path to the KeyStore and password created in the previous step.

    <java classname="Launcher" 
          classpathref="java.sdk.classpath" fork="true">         
        <sysproperty key="javax.net.ssl.keyStore"
                     value="/insert/your/path/java-keystore.jks" />
        <sysproperty key="javax.net.ssl.keyStorePassword" 
                     value="insert_your_password" />
    </java>
    

Running the Sample from the Command Line

Build and run the sample using Maven (mvn):

  1. In a command-line terminal, navigate to <alexa-skills-kit-folder>/samples. This folder contains the pom.xml file you previously edited.
  2. Build the samples with the following Maven command:

mvn assembly:assembly -DdescriptorId=jar-with-dependencies package

  1. Once the samples are successfully built, run the sample with the following Maven command:

mvn exec:java -Dexec.executable=”java” -DdisableRequestSignatureCheck=true

The sample starts a server using the Launcher class. You can then use the command-line utility cURL to transmit HTTPS requests to the sample to test its behavior. Note that the Maven command to run the samples includes the disableRequestSignature flag. This is because the SpeechletServlet included in the Java library only accepts incoming HTTPS requests that are signed by Alexa. The disableRequestSignature flag temporarily disables this signature verification.

To send a request using cURL, open a new terminal window and transmit a request to https://localhost:8888/hello formatted as JSON. For example (JSON shown on multiple lines for clarity):

curl -v -k https://localhost:8888/hello --data-binary  '{
  "version": "1.0",
  "session": {
    "new": true,
    "sessionId": "session1234",
    "application": {
      "applicationId": "amzn1.echo-sdk-ams.app.1234"
    },
    "attributes": {},
    "user": {
      "userId": null
    }
  },
  "request": {
    "type": "LaunchRequest",
    "requestId": "request5678",
    "timestamp": "2015-05-13T12:34:56Z"
  }
}'

For details about the JSON syntax for a launch request, see JSON Interface Reference for Custom Skills.

The Hello World sample generates a simple response to all requests that includes text meant to be spoken back by Alexa and a card displayed in the Alexa App. The body of this response is in JSON format, similar to the following:

{
  "version": "1.0",
  "response": {
    "outputSpeech": {
      "type": "PlainText",
      "text": "Welcome to the Alexa Skills Kit, you can say hello"
    },
    "card": {
      "type": "Simple",
      "title": "HelloWorld",
      "content": "Welcome to the Alexa Skills Kit, you can say hello"
    },
    "reprompt": {
      "outputSpeech": {
 "type": "PlainText",
 "text": "Welcome to the Alexa Skills Kit, you can say hello"
      }
    },
    "shouldEndSession": false
  },
  "sessionAttributes": {}
}

Setting up Hello World on Elastic Beanstalk

To test a skill with the Service Simulator or an Alexa-enabled device, you need to host the web service for the Alexa skill at an Internet-accessible endpoint. There are many different ways you can accomplish this. One possible method is to host the skill on AWS Elastic Beanstalk (a service offering by Amazon Web Services). These steps walk you through setting up the Hello World sample on Elastic Beanstalk.

Deploying Hello World to AWS Elastic Beanstalk requires the following tools, in addition to the Java requirements noted earlier:

In these instructions, <alexa-skills-kit-folder> is the folder you cloned from the GitHub repository.

To deploy a sample to Elastic Beanstalk, do the following:

  1. Download or clone the amzn/alexa-skills-kit-java GitHub repository.
  2. If you do not already have an account on AWS, go to Amazon Web Services and create an account.
  3. Install the AWS Toolkit for Eclipse.
  4. Configure the AWS Toolkit for Eclipse with your account credentials: a. Log in to the AWS Console and navigate to Identity and Access Management (IAM). b. Create a new IAM user and grant the user full access to Elastic Beanstalk. c. Select the option to generate an access key for the new user. Choose to download these credentials. d. In Eclipse, click on Window and then Preferences. In the AWS Toolkit section, enter your Access Key ID and Secret Access Key.

  5. Run Maven once to add the Alexa Skills Kit Java library (alexa-skills-kit-x.x.jar) to your local repository: a. In a command line, navigate to <alexa-skills-kit-folder>/samples. b. Run the command: mvn install.

    This copies the compiled jar file from <alexa-skills-kit-folder>/repo into your local Maven repository, so it will be available when you build the sample later.

  6. Create a new Maven project using the maven-archetype-webapp archetype and import the sample code. See Creating the Maven Webapp Project and Importing the Code.
  7. Add a class that extends SpeechletServlet to host the HelloWorldSpeechlet and set up servlet mapping in web.xml. See Adding a SpeechletServlet and Setting up Servlet Mapping.
  8. Deploy the project to AWS Elastic Beanstalk. See Deploying the Sample to Elastic Beanstalk.
  9. Configure the new Elastic Beanstalk environment to use HTTPS. See Configuring the Elastic Beanstalk Environment to Use HTTPS.
  10. Register the sample in the Developer Portal. See Registering the Sample in the Developer Portal.
  11. Test the skill with either the Service Simulator on the developer portal, or an Alexa-enabled device registered to your developer portal account. See Testing the Sample.

Creating the Maven Webapp Project and Importing the Code

The Maven maven-archetype-webapp archetype creates a new project that is structured as a web application and set up to build with Maven.

When setting up your project, note that you can drag files and folders from your file system into Eclipse. When prompted, select the option to copy the files into the project.

  1. In Eclipse, click File > New > Maven Project.
    • If this option is not available, choose File > New > Project, expand Maven and select the Maven Project option.
    • If Maven is not shown in the New Project dialog box, make sure that your version of Eclipse includes Maven Integration for Eclipse.
  2. Select a location for the project. Make sure the Create simple project option is not selected.
  3. When prompted to select an archetype, select maven-archetype-webapp. Note that the list of archetypes is long, so you may want to filter it by typing “webapp” in the filter box.
  4. Enter a Group Id and Artifact Id for the project. For instance, you can set both of these fields to alexa-skills-kit-samples.

This creates a new, blank project set up as a web app. You now need to add the sample source code and dependencies:

  1. The project should have a src/main folder. If main does not already contain a java folder, create a new folder called java. The end result should be a structure like this: src/main/java.
  2. Copy the helloworld folder from <alexa-skills-kit-folder>/samples/src/main/java into the src/main/java folder in the new project.
    • You can do this either by dragging helloworld into eclipse and selecting the Copy files and folders option, or copying the folder within the file system.
    • The project should now contain a single package called helloworld, containing two classes (HelloWorldSpeechlet and HelloWorldSpeechletRequestStreamHandler. Note that the second class is provided for Lambda and not used in this example).
  3. Copy the file <alexa-skills-kit-folder>/samples/pom.xml into the root of the Maven project, replacing the pom.xml that was generated when creating the project. The pom.xml provided with the samples is already setup with all of the dependencies necessary to build the sample. However, it is set up to build a JAR file rather than a WAR.
  4. Edit the pom.xml file and make the following changes:
    • Change the <packaging> setting to war.
    • Under <build>, add the following line: <finalName>alexa-skills-kit-samples</finalName>
  5. Right-click on the project, click Maven and then click Update Project.

Adding a SpeechletServlet and Setting up Servlet Mapping

The Java library includes a SpeechletServlet class. This implementation of a Java EE servlet handles serializing and deserializing the body of the HTTP request and calls the appropriate Speechlet methods based on the request (onLaunch(), onIntent, and so on).

To host your web service on Elastic Beanstalk, you need to extend this class and add a constructor that instantiates the appropriate Speechlet class in the sample (HelloWorldSpeechlet). Then, set up servlet mapping in the web.xml file for the project.

To create the SpeechletServlet:

  1. In the helloworld package, create a new class that extends com.amazon.speech.speechlet.servlet.SpeechletServlet. For this example, name the new class HelloWorldServlet.
  2. Implement a default constructor for the new class that instantiates HelloWorldSpeechlet by calling setSpeechlet().

The HelloWorldServlet class should look like this:

package helloworld;

import com.amazon.speech.speechlet.servlet.SpeechletServlet;

public class HelloWorldServlet extends SpeechletServlet {

  public HelloWorldServlet() {
    this.setSpeechlet(new HelloWorldSpeechlet());
  }
}

To set up the servlet mapping:

  1. Open the src/main/webapp/WEB-INF/web.xml file in the project.
  2. Add the <servlet> and <servlet-mapping> tags to identify the servlet class and map the class to a URL.

The <servlet> and <servlet-mapping> sections should look like this:

<servlet>
  <servlet-name>HelloWorldServlet</servlet-name>
  <servlet-class>helloworld.HelloWorldServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>HelloWorldServlet</servlet-name>
  <url-pattern>/hello</url-pattern>
</servlet-mapping>

After making all of these updates, save all files, then right-click on the project, click Maven and then click Update Project.

At this point, the project should be fully set up. Do a build just to ensure that everything builds correctly. Right-click the project, click Run As and then click Maven install. Verify that a war file is created in the target folder for the project.

Deploying the Sample to Elastic Beanstalk

You can deploy web project directly from Eclipse if you are using the AWS Toolkit for Eclipse. The initial deployment creates a new application and environment. An environment represents a particular version of a web service, deployed onto AWS resources. The environment name is used to determine the endpoint for the web service. See Elastic Beanstalk Components for more information.

Once the web service is deployed, you can make code changes in Eclipse and re-deploy to the same environment. This updates the environment with a new version of your web service.

AWS Pricing: There is no extra charge to use Elastic Beanstalk. You pay for the actual AWS resources your application uses (such as EC2). Note that pricing for EC2 usage differs between regions – see Amazon EC2 Pricing for details.

To deploy the Hello World sample to Elastic Beanstalk:

  1. Use Maven to build a war file for the project: Right-click the project, click Run As and then click Maven install. Verify that a war file is created in the target folder for the project.
  2. In the Eclipse Project Explorer, right-click the project and click Amazon Web Services then Deploy to AWS Elastic Beanstalk.
  3. Select the Manually define a new server option.
  4. For the server type, select AWS Elastic Beanstalk for Tomcat 8, then click Next.
  5. Select the Region where you want to deploy the application.

    Note: All calls from Alexa come from the US East (N. Virginia) AWS region. Therefore, for best performance and reduced cost, create your Elastic Beanstalk environment in the US East (N. Virginia) region.

  6. Enter an Application Name and Environment Name and click Finish.

Deploying the application to Elastic Beanstalk may take several minutes.

At this point, you should be able to connect to the environment in a browser. However, your service cannot take requests from Alexa until you configure the environment to use HTTPS.

Configuring the Elastic Beanstalk Environment to Use HTTPS

To meet the security requirements of Alexa, the endpoint for your web service must present a valid SSL certificate. When testing on Elastic Beanstalk, you can use a self-signed certificate for this. You need to configure the Elastic Beanstalk environment to present the signed certificate.

You do this by uploading your certificate as a server certificate and then configuring the Elastic Beanstalk Load Balancer for your environment to use HTTPS.

  1. Create a private key and self-signed certificate.
    • See the detailed instructions in Testing a Custom Skill. Be sure to specify the domain name for your new Elastic Beanstalk endpoint when creating the certificate.
    • Make a note of the .pem files for your certificate and private key.
  2. Install and configure the AWS Command Line Interface if you have not already done so.

  3. Use the following AWS command to upload your self-signed certificate to AWS as a server certificate.

     aws iam upload-server-certificate \
       --server-certificate-name CertificateName \
       --certificate-body file://path/to/certificate.pem \
       --private-key file://path/to/private-key.pem
    
    • For the server-certificate-name, specify a name to identify the certificate in AWS.
    • For the certificate-body, specify the path and filename of the .pem file for the certificate.
    • For the private-key, specify the path and filename of the .pem file for your private key.
  4. Log in to the AWS Management Console. Navigate to Elastic Beanstalk and then navigate to your new environment.
  5. In the left menu, click Configuration, then open the Load Balancing section.
  6. Make the following changes:

    • Set Secure listener port to 443.
    • Set Protocol to HTTPS.
    • From the SSL Certificate ID drop-down list, select the name of the server certificate you uploaded in step 3.
  7. Save your changes. Elastic Beanstalk automatically updates your environment.
  8. Verify you can connect to your environment’s URL from a browser using the https:// protocol.

Registering the Sample in the Developer Portal

Finally, you need to register the sample in the developer portal. This makes it possible for you to test it. You don’t need to fully complete all registration fields. For testing, you must enter at a minimum:

  • Skill Information: Skill Type (Custom Interaction Model), Name, and Invocation Name.
  • Interaction Model: Intent Schema, Sample Utterances, and Custom Slot Types.
  • Configuration: Endpoint. Select the HTTPS option and enter the URL for your service’s endpoint.
  • SSL Certificate: Select one of the options. If you want to use a self-signed SSL certificate for testing, create that certificate and upload it to the Developer Portal.
  • Test: Set to Enabled.

For the steps to register the skill, see Registering and Managing Custom Skills in the Developer Portal. Use the values in the following table.

Setting Value
Name Any valid skill name
Invocation Name Any valid invocation name. For instance, you can use “greeter.”
Interaction Model Each sample includes a speechAssets folder that contains a sample interaction model. Copy the JSON from IntentSchema.json into the Intent Schema box and copy the text from SampleUtterances.txt into the Sample Utterances box.

For details about how these are used in the sample skills, see Using the Alexa Skills Kit Samples (Custom Skills).
Endpoint Select the HTTPS option and then enter the endpoint defined by your Elastic Beanstalk environment. Be sure to include the full path based on the <url-pattern> you set in your servlet mapping.

For example, if <url-pattern> is /hello and your Elastic Beanstalk environment endpoint is https://myhelloworldskill.elasticbeanstalk.com, set the Endpoint to:

https://myhelloworldskill.elasticbeanstalk.com/hello
SSL Certificate Select the I will upload a self-signed certificate option. Then open the certificate you previously generated in a text editor and copy the entire contents into the text box

Testing the Sample

Once the sample is deployed to Elastic Beanstalk, configured for HTTPS, and registered on the developer portal, you should be able to invoke the skill by saying one of the phrases for interacting with skills:

  • “Alexa, ask <invocation name> to <command>.”
  • “Alexa, tell <invocation name> to <command>.”
  • “Alexa, talk to <invocation name>

For a list of supported phrases, see Supported Phrases to Begin a Conversation. For details about the provided samples and possible intents, see Using the Alexa Skills Kit Samples (Custom Skills).

If you want to experiment with changes, make your code changes in the project and then re-deploy the code to Elastic Beanstalk. You can re-deploy to the same Elastic Beanstalk environment:

  1. In the Eclipse Project Explorer, right-click the project and choose Amazon Web Services > Deploy to AWS Elastic Beanstalk.
  2. In the Run On Server dialog box, select Choose an Existing Server, select the existing environment to which you want to deploy the web service, then click Finish.

Accessing Log Files

Log files can be very useful when debugging and troubleshooting. In an Elastic Beanstalk configuration set up as described here, you can access log files for the web service in three ways:

  1. View a snapshot of the log files from the AWS Console. This snapshot includes the last 100 lines from each log file, all in a single view or download.
  2. Download all the logs from AWS Console.
  3. Configure your Beanstalk environment to automatically publish the logs to AWS S3 bucket.

For details about these different options, see Working with Logs.

The provided samples use SLF4J and log4j for logging. By default this writes log messages to the console terminal. To write log messages to a log file stored with your Elastic Beanstalk environment, you need to configure the logger with a log4j.properties configuration file. Add this file to the Java Resources\src directory in your Java Web Project.

For example, the following log4j.properties file configures the logger to write log entries to a file called /var/log/tomcat8/helloworld.log:

log4j.logger.helloworld=info
log4j.rootLogger=info, tail

log4j.appender.tail=org.apache.log4j.FileAppender
log4j.appender.tail.File=${catalina.base}/logs/helloworld.log
log4j.appender.tail.layout=org.apache.log4j.PatternLayout
log4j.appender.tail.layout.ConversionPattern=%d: %-5p %c{1} - %m%n

See SLF4J and log4j for information about configuring logging.

The HelloWorldSpeechlet writes a log entry for each type of request the service receives:

private static final Logger log = LoggerFactory.getLogger(HelloWorldSpeechlet.class);
...

@Override
public SpeechletResponse onLaunch(final LaunchRequest request, final Session session)
      throws SpeechletException {
    log.info("onLaunch requestId={}, sessionId={}", request.getRequestId(),
     session.getSessionId());
    ...
}

Using the above configuration and launching Hello World generates log entries similar to the following (as viewed in the snapshot of the last 100 lines of logs in Elastic Beanstalk):

-------------------------------------
/var/log/tomcat8/helloworld.log
-------------------------------------
2015-03-27 18:06:48,976: INFO  HelloWorldSpeechlet - onSessionStarted requestId=amzn1.echo-api.request.affeb267-c275-4f43-91ed-620fce5851ab, sessionId=amzn1.echo-api.session.8767a9df-45b2-4525-a376-5b3c8ba3f715
2015-03-27 18:06:49,087: INFO  HelloWorldSpeechlet - onLaunch requestId=amzn1.echo-api.request.affeb267-c275-4f43-91ed-620fce5851ab, sessionId=amzn1.echo-api.session.8767a9df-45b2-4525-a376-5b3c8ba3f715

Next Steps