7. Setup your AWS Services Account
● https://aws.amazon.com/
● Does require a credit card
● Does have a free tier which is great
Nothing we will be doing here, will incur a cost.
8. Alexa Github Repos
● https://github.com/alexa
● Lots of great examples and templates.
● The Repos have a lot of the getting started information in them
9. Starting Our First Alexa Skill
● Login at https://aws.amazon.com/ with your AWS Services account
● We are going to start with Lambda, so go to Services and click on Lambda
under the Compute heading.
● Click ‘Create a function’ on the Lambda page.
10.
11. Lambda - Node
Yes Brad, we’re going to look at writing a
Lambda in NodeJS.
18. How to get your Skill ID
Later when we have created our Alexa Skill, if you pick a Lambda endpoint, you
will see this.
Copy this and come back here to update your Skill ID
25. But I’m a programmer
● You don’t like using a mouse?
● Can’t handle typing and clicking and waiting?
Don’t fret, there is a JSON editor, so we can cheat a little.
Lets get some JSON from the Alexa Github repos
https://github.com/alexa/skill-sample-nodejs-fact
36. Adding Slots
Adding slots into your utterances really give your Alexa App power.
You can pass information into your endpoint with these slots, and customize the
experience.
Alexa ask Forgebox how many hits does {kiwiSays} have?
These are similar arguments to your function.
Note: there were some difficulties with slots.
37.
38. Slot Requirements and Confirmation
For a given Slot, you can set it as required. This allows you and Alexa to ask for
this slot directly to ensure you have all the data you need.
You can also confirm a slot. You can tell Alexa what to ask, what to expect in
response and how to confirm.
Alexa: What package would you like me to lookup?
You: KiwiSays or Lookup KiwiSays
Alexa: Ok, so you want me to lookup KiwiSays?
You: Yes
39.
40.
41. Issues with Slots
Alexa does not automatically process the Dialog for you.
You get a list of the slots, but they are not always defined. An error in your
Lambda can break your skill.
You should be able to return a Dialog.delegate and then Alexa will process until
complete… but I had issues with this.
42. Building a REST API to talk to
● We will be looking at ColdBox REST today
● Its easy to add onto existing ColdBox Apps
● Or start a new app with our AdvancedScript or REST skeleton
● REST Template does most of the REST boilerplate for you
● You can just do your thing
43. Scaffold our App
CommandBox has a lot of create commands, today we’ll use the
ColdBox Create App command.
We could specify a skeleton to use when creating the ColdBox app so we can hit
the ground running. We could use the REST Skeleton which you can find out more
about here: https://www.forgebox.io/view/cbtemplate-rest
You could make your own template and use that from ColdBox Create App ( even
if it wasn’t coldbox )
The default is advancedScript - which is fine for this example.
44. Run our CommandBox command
Coldbox create app name=myAPI skeleton=rest
This will download the REST template, and do a box install.
Start commandbox and you’ll see your first API response.
http://127.0.0.1:55944/
{
"data": "Welcome to my ColdBox RESTFul Service",
"error": false,
"messages": []
}
45. Lets create a new Handler for Forgebox
component extends="handlers.BaseHandler"{
function downloads( event, rc, prc ){
event.paramValue( "slug", "kiwisays" );
var result = "";
cfhttp( method="GET", charset="utf-8",
url="https://www.forgebox.io/api/v1/entry/#rc.slug#", result="result" );
var jsonResponse = deserializeJSON( result.filecontent );
if( jsonResponse.error ){
prc.response.setError( true );
prc.response.addMessage( "Error finding Slug" );
} else {
prc.response.setData( jsonResponse.data.hits );
}
}
46. Lets create a RESTful Route
Add this to your routes file: /config/routes.cfm
addRoute(
pattern = "/forgebox/entry/:slug/:action",
handler = "forgebox"
);
47. Reinit App and Test the endpoint
Reinit the app
http://127.0.0.1:55944/?fwreinit=1
Test the endpoint
http://127.0.0.1:55944/forgebox/entry/kiwisays/downloads
{
"data": 1432,
"error": false,
"messages": []
}
48. Why are we using a API to call an API
Short Answer: NODE
Using a Lambda, you are using Node.
Node doesn’t support http and https requests natively, so you install a module
for that.
HTTPS is a great tool, BUT if you want to hit an HTTPS site, you have to
manually install the SSL cert. So you can load files on the fly to make the call…
or you can call a ColdFusion API and let cfhttp do it for you :)
50. Create a Lambda for API Call
Here is a Gist of a lambda function
https://gist.github.com/gpickin/4a57d996df15079abb7b7136e25bf414
51. Parts of the Lambda - Handlers
Handlers work just like an MVC framework. This index.js file gets the call, and
decides how to return to it.
const handlers = {
'LaunchRequest': function () {
this.emit('forgeboxDownloads');
},
52. Parts of the Lambda - ForgeboxIntent & Slots
Slots are available in a struct.
Warning - if that slot was not provided, an undefined will force the lambda to return
an null response. BOOM
'forgeboxDownloads': function () {
let slug = "kiwisays";
slug = this.event.request.intent.slots.slug.value;
53. Parts of the Lambda - Setup the API Call
// npm install http in CLI and then require it
const http = require('http');
// Setup the options for the HTTP request
const options = {
hostname: 'edf6f5f8.ngrok.io',
port: 80,
path: '/forgebox/entry/' + slug + '/downloads',
method: 'GET'
};
54. Parts of the Lambda - Make API Call
// Store this for inside of closure
const $this = this;
// Make the request
const req = http.request(options, (res) => {
res.setEncoding('utf8');
res.on('data', function (chunk) {
//console.log('BODY: ' + chunk);
const bodyString = chunk;
const bodyObject = JSON.parse( chunk );
// process the json
});
});
55. Parts of the Lambda - Process the API Response
if( bodyObject.error ){
const speechOutput = 'Error loading data';
$this.response.cardRenderer(SKILL_NAME, speechOutput);
$this.response.speak(speechOutput);
$this.emit(':responseReady');
} else {
const speechOutput = GET_FACT_MESSAGE + 'The package with the slug ' +
slug + ' has ' + bodyObject.data + ' hits';
$this.response.cardRenderer(SKILL_NAME, 'The package with the slug ' + slug + '
has ' + bodyObject.data + ' hits');
$this.response.speak(speechOutput);
$this.emit(':responseReady');
}
56. Parts of the Lamba - Catch API Errror
req.on('error', (e) => {
console.error(e);
const speechOutput = 'Error loading data';
$this.response.cardRenderer(SKILL_NAME, speechOutput);
$this.response.speak(speechOutput);
$this.emit(':responseReady');
});
57. Parts of a Lambda - Close the Connection
// Node gives you the tools, but you have to do everything
yourself… including close the request
req.end();
58. Let’s Test it with Alexa
ask gavin the amazing how many hits does commandbox-migrations have
● Ask - prefix to Invocation name
● Gavin the amazing - the Invocation name
● How many hits does {slug} have - Utterance to call forgeboxIntent
● Commandbox-migrations - this is the slot called slug
This will call our Lambda function
61. Alexa SDK
There are SDKs for NodeJS, Java etc, but not CFML…. But that’s ok.
They have a JSON version you can setup with an HTTPS endpoint.
Thanks to Steve Drucker’s repo, we had a solid starting point
https://github.com/sdruckerfig/CF-Alexa
Note: I had to make a lot of changes to get it to work.
62. Alexa.cfc
This is the base object, with the core functions you need to interact with Alexa
Included Functions:
● say()
● setTitle()
● setText()
● setImage()
● And many more.
To use this, you extend Alexa.cfc in your Service ( AlexaBot in this example )
63. AlexaBot.cfc
This is your template for your service.
Define your Intents
Create functions to handle your incoming Intents
Functions respond to Alexa with JSON returns
Alexa.cfc handles the DSL to do the hard work for you.
65. AlexaBot.cfc - Add function to respond
Use the Alexa DSL to respond to Alexa
Your response can set the Alexa CARD with title & text and/or Speech
public void function testAPI( ){
say( "Coldbox is ICE cold" );
setTitle( "How cool is Coldbox?" );
setText( "Coldbox is ICE cold" );
}
66. AlexaBot.cfc - Use slots as arguments
public void function makeMeAMeme( memeTemplate="", lineOne="", lineTwo=""
){
if( memeTemplate == "" ){
say( "What meme template would you like?" );
}
}
67. Setup the API Route for Alexa
Add to your routes file
{
pattern = "/alexa",
handler = "Main",
action = { GET = "alexa", POST = "alexa" }
},
68. Setup the API Handler for Alexa
function alexa( event, rc, prc ){
var content = getHttpRequestData().content;
var alexaBot = new models.Alexa.alexabot(); // or use wirebox with
getInstance()
prc.response.setData( alexaBot.get( content ) );
prc.response.setRaw( true ); // New to REST response model
}
69. Test the API Endpoint
Return to the Alexa Developer Tools
You: ‘ask gavin the cool how cold is coldbox’
Alexa: ColdBox is ICE cold
You: ‘ask gavin the cool make me a meme’
Alexa: Meme Generated
Visit to view meme: http://127.0.0.1:55944/models/Alexa/index.html
71. What’s next?
I hope this was a good introduction to using Alexa, and ColdBox APIs
● We have a lot more information on REST in our REST Roadshow we
recorded in 2016
https://www.ortussolutions.com/events/restful-roadshow-2016
● Check out our blog on Ortussolutions.com
● We offer training online and in person
● We have Brad the monkey manning slack 34 hours a day.
ColdBox REST is simple, lots more support in ColdBox 5, and all the ForgeBox
modules at your disposal
72. Thanks
I hope you enjoyed the session.
Visit www.gpickin.com to see my follow up blog post with links to code and slides.
Don’t forget to come see my ContentBox + Docker - Friday at 3:25pm
Got questions? Find me at Happy Box right after this session and the live panel
podcast recording.