alexa-router v2.0.0
alexa-router
Why
alexa-router makes it easy for you to build custom Alexa
skills with complex request/response flows.
Install
$ npm install -S alexa-routerUsage
alexa-router is available via an instance of the Router. Make sure you begin by initializing the
Router.
let Alexa = require('alexa-router')
let alexa = new Alexa.Router({
  appId: 'my-app-id'
})Once you initialize the router, you can either configure actions or dispatch a HTTP request to be
routed to the actions you have configured.
Router
API
new Alexa.Router(config)
config
Required 
Type: Object
config.appId 
Required  
Type: String[]
Your application ID or an array with many
config.routeIntentOnly 
Optional  
Type: Boolean 
Default: true
Try to route IntentRequest only
config.verifySignature 
Optional  
Type: Boolean 
Default: true
Verifies the incoming request against a valid Amazon signature to prevent request forgery. Amazon requires verification as part of the skill submission process
config.verifyTimestamp 
Optional  
Type: Boolean 
Default: true
Verifies if the incoming request have a valid timestamp to prevent replay attacks
config.verifyAppId 
Optional  
Type: Boolean 
Default: true
Verifies if the incoming request have a valid application ID to prevent replay attacks from other applications
Examples
let alexa = new Alexa.Router({
  appId: 'my-id',
  verifySignature: false
})alexa.action
Routes are defined via the action method
API
alexa.action(name, config)
name
Required 
Type: String
The action name. You can reference this action by its name when defining complex action flows.
config
Required 
Type: Object
config.handler(request[, params]) 
Required 
Type: Function
The handler receives a decorated HTTP request and optionally receives params if they were configured to be passed by a previous action.
request
Type: Object
The decorated Alexa Request Body(https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interface-reference#Request Format) with additional methods.
request.next() 
Returns: Array 
An array of Next Action Objects set by the previous response in the session
request.response() 
Returns: Object 
A decorated Alexa Response Object
// Instantiate a new Response object
let response = request.response()response.session(key, value)
Param: key String
Param: value String|Object
Sets, patches, or retrieves the session's attributes
response.speech(text)
Param: text String
Convenience method to set speech with raw text or SSML
response.reprompt(text)
Param: text String
Convenience method to set reprompt with raw text or SSML
response.card(card) 
Param: card Object a valid Alexa Card Object(https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/alexa-skills-kit-interface-reference#Response Format) 
Convenience method to set the response card
response.endSession(shouldEndSession) 
Param: shouldEndSession Boolean 
A convenience to set the response shouldEndSession property
response.clearSession() 
Clears the current session
response.next(config) 
Param: config Object|Array 
If you pass an object it will be merged with any previous Next Action Objects that were passed
      The Next Action Object 
      type 
      Required 
      Type: String
One of 'intent', 'launch', 'sessionEnded', or 'unexpected'
      action 
      Required 
      Type: String 
The name of the action that should be called if this route is activated
      intent 
      Required if type === 'intent' 
      Type: String
The custom or built-in intent that this action should be associated with. e.g. 'AMAZON.YesIntent'
      params 
      Optional 
      Type: Any
Any data you'd like to pass to follow request if this route is activated
params
Type: Object
Params set by a previous action
config.global 
Optional 
Type: Object
Actions with the global key are accessible at any point in the routing flow (like a catch-all). These actions can be used to kick-off a new flow, interrupt an existing flow, etc. An action to help the user know what commands are available or cancel the request are two examples for where you might use a global action.
config.global.type 
Required 
Type: String
One of 'intent', 'launch', 'sessionEnded', or 'unexpected'
config.global.intent 
Required if type === 'intent' 
Type: String
The custom or built-in intent that this action should be associated with. e.g. 'AMAZON.YesIntent'
Examples
A simple action that can be activated by an incoming intent
alexa.action('global-hello', {
  handler: request => {...},
  global: {
    type: 'intent', // Could also be launch, sessionEnded or unexpected
    intent: 'AMAZON.YesIntent'
  }
})You can also chain requests by responding with a list of possible actions that could be next in the interaction flow
alexa.action('event-create', {
  handler: request => {
    let response = request.response()
    response.speech('What\'s the name of your event?')
    // You can define the next actions by passing an array of actions that can come next
    response.next([
      {
        type: 'intent',
        intent: 'EventName', // Custom intent
        action: 'event-create-name'
        params: { createdAt: new Date() } // Params will be passed to the `event-create-name` handler
      },
      {
        type: 'intent',
        intent: 'AMAZON.CancelIntent', // Built-in intent
        action: 'event-cancel'
      }
    ])
    // You can also pass an individual object and it will be merged with the previous ones
    response.next({
      type: 'unexpected',
      action: 'event-unexpected'
    })
    return response
  },
  global: {
    type: 'intent',
    intent: 'EventCreate' // Custom intent
  }
})
// This action does not have the global attribute so it can only be accessed if passed
// as a `next` action
alexa.action('event-create-name', {
  handler: (request, params) => {...}
})alexa.dispatch
The dispatch method takes a HTTP request and routes it to the appropriate action
API
alexa.dispatch(requestBody, headers)
requestBody
Required Type: 'Object'
The HTTP request body
Headers
Required Type: 'Object'
The headers present in the original incoming request
Understanding the routing mechanism
- Check if the incoming request was configured with 
nextactions - If 
nextactions are present, try to resolve the next action - If no action was resolved, check for an 
unexpectedtypenextoption - If no next actions are present in the request's session, try to match a global action
 - If no global action was found try to find an 
unexpectedglobal action - If no 
unexpectedglobal action then throwRoutingFailed 
HTTP handling
alexa-router is HTTP server agnostic. This means that you can use it with
any Node.js library that can parse and reply JSON. An example using Express:
let express = require('express')
let bodyParser = require('body-parser')
let Alexa = require('alexa-router')
let app = express()
let alexa = new Alexa.Router({
  appId: 'my-app-id'
})
// Do all your routing configs
alexa.action('my-action', ...)
// Configure a route for passing JSON to alexa-router
app.post('/alexa/incoming', bodyParser.json(), (req, res) => {
  alexa.dispatch(req.body, req.headers)
  .then(result => res.json(result))
  .catch(err => {
    res.send('Somthing bad happened...').status(500)
  })
})To-do
- Add plugin support
 - Add more testing cases
 - Build plugins for Express, Hapi, Restify (...)
 
Testing
git clone https://github.com/estate/alexa-router && cd alexa-router
npm install && npm test