Host Alexa skill on AWS with Serverless
This post first appeared on dev.to
Hey all :wave: we are gonna see how to setup an Alexa skill for a trivia related to space events, using the Serverless framework. It’s assumed you are ok with some Alexa fundamentals and certain concepts of AWS such as IAM, Lambda etc. Let’s get started.
You may go through this nice tutorial if you want to get started with Alexa by building an Alexa hosted skill. What we have done here in this blog is an AWS hosted skill.
Alexa
Login to the Alexa skill kit console with your developer account.
You can then create a skill and give it some invocation name.
Intents
I’ve addedd 2 built-in intents and 2 custom intents, than what gets added by default.
The GetAnswerIntent has the following utterances.
it's {date}
I guess it's on {date}
I think the date is {date}
{date}
I'm guessing it's {date}
You may add more or modify as you wish. The only slot here is date
and it is of built-in type AMAZON.DATE.
Likewise the AskQuestionIntent has the following utterances.
could you ask me the question please
can you go back to the question
can you ask me the question
question please
go back to the question
next question
Ask question
Ensure to save and build the model once all the intents are added.
IAM
Log in to AWS as a root user, and create a user group
The user group should be attached by the AWS managed permission policy AWSCloud9User that allows creating Cloud9 environments. This is not required though, if you are not using Cloud9.
I’ve then created another custom policy with the following JSON, with the name ServerlessPolicy
that gives enough permissions for the serverless SDK to deploy using cloud formation stack, and access to other relevant services as listed.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"apigateway:DELETE",
"apigateway:GET",
"apigateway:PATCH",
"apigateway:POST",
"apigateway:PUT",
"cloudformation:CreateChangeSet",
"cloudformation:CreateStack",
"cloudformation:DeleteChangeSet",
"cloudformation:DeleteStack",
"cloudformation:DescribeChangeSet",
"cloudformation:DescribeStackEvents",
"cloudformation:DescribeStackResource",
"cloudformation:DescribeStacks",
"cloudformation:ExecuteChangeSet",
"cloudformation:ListStackResources",
"cloudformation:UpdateStack",
"cloudformation:ValidateTemplate",
"events:DescribeRule",
"events:PutRule",
"events:PutTargets",
"events:RemoveTargets",
"iam:CreateRole",
"iam:DeleteRole",
"iam:DeleteRolePolicy",
"iam:GetRole",
"iam:PassRole",
"iam:PutRolePolicy",
"iam:UpdateAssumeRolePolicy",
"lambda:AddPermission",
"lambda:CreateFunction",
"lambda:DeleteFunction",
"lambda:GetAccountSettings",
"lambda:GetAlias",
"lambda:GetEventSourceMapping",
"lambda:GetFunction",
"lambda:GetFunctionConfiguration",
"lambda:GetLayerVersion",
"lambda:GetLayerVersionPolicy",
"lambda:GetPolicy",
"lambda:InvokeFunction",
"lambda:ListAliases",
"lambda:ListEventSourceMappings",
"lambda:ListFunctions",
"lambda:ListLayerVersions",
"lambda:ListLayers",
"lambda:ListTags",
"lambda:ListVersionsByFunction",
"lambda:PublishVersion",
"lambda:RemovePermission",
"lambda:UpdateFunctionCode",
"lambda:UpdateFunctionConfiguration",
"logs:CreateLogGroup",
"logs:DeleteLogGroup",
"logs:DeleteSubscriptionFilter",
"logs:DescribeLogGroups",
"logs:FilterLogEvents",
"logs:GetLogEvents",
"logs:PutSubscriptionFilter",
"s3:CreateBucket",
"s3:DeleteBucket",
"s3:DeleteBucketPolicy",
"s3:DeleteBucketWebsite",
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:GetBucketLocation",
"s3:GetObject*",
"s3:ListBucket",
"s3:PutBucketPolicy",
"s3:PutEncryptionConfiguration",
"s3:PutObject",
"sts:GetCallerIdentity"
],
"Resource": "*"
}
]
}
So the group is attached to both policies.
Once the group is created, add a new user to the group.
And don’t forget to copy the credentials
Instance
You may now login to AWS as the new user. Next we need a machine from which we can clone the serverless code and deploy it, for this purpose I would be launching a cloud 9 instance, so that I can also use it as an online editor. You can use any Linux machine though.
I’d be creating a Cloud9 environment in the Mumbai region, ap-south-1. I’ve choosen t3.small as the instance type, we may go with t2.micro if we want a free tier eligible instance.
Once it’s created you shoud see the console.
AWS CLI
AWS CLI comes pre-installed in Cloud9 and it would also have the credentials file
serverless-user-1:~/environment $ ls ~/.aws/
credentials
We can setup the config though.
serverless-user-1:~/environment $ cat ~/.aws/config
[default]
region=ap-south-1
Clone
Let’s clone the alexa skill repo space-events-trivia from github.
serverless-user-1:~/environment $ git clone https://github.com/networkandcode/space-events-trivia.git
The code we cloned is a set of nodejs functions and is compatible with the serverless sdk.
serverless-user-1:~/environment $ cd space-events-trivia/
serverless-user-1:~/environment/space-events-trivia (main) $ ls
AplRender.js GetAnswerIntentHandler.js interceptors.js README.md StartTriviaHandler.js
CancelAndStopIntentHandler.js HelpIntentHandler.js LaunchRequestHandler.js RepeatIntentHandler.js triviaFunctions.js
documents index.js package.json serverless.yml
ErrorHandler.js IntentReflectorHandler.js package-lock.json SessionEndedRequestHandler.js
The file documents/questions.json contains the list of questions for the trivia, you may modify it as required.
Packages
The package.json file should tell us the packages we would be using in our code.
Let’s install those.
serverless-user-1:~/environment/space-events-trivia (main) $ npm i
npm WARN deprecated querystring@0.2.0: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
npm WARN deprecated uuid@3.3.2: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
added 18 packages, and audited 19 packages in 2s
1 package is looking for funding
run `npm fund` for details
found 0 vulnerabilities
Serverless
We can install the serverless SDK and later deploy the code using it to AWS lambda. We are actually talking about two things here, one the serverless framework/SDK, and two the serverless technology offering from AWS which is Lambda. Instead of writing the functions directly on Lambda we are going to use the serverless SDK with it’s constructs to acheieve the purpose in a controlled way.
serverless-user-1:~/environment $ npm i serverless -g
It should now be installed.
serverless-user-1:~/environment $ serverless -v
Framework Core: 3.18.2
Plugin: 6.2.2
SDK: 4.3.2
There is a serverless.yml file in our repo, that has our serverless configuration, you may modify it according to your setup.
serverless-user-1:~/environment/space-events-trivia (main) $ cat serverless.yml
app: space-events-trivia
service: space-events-trivia
frameworkVersion: '3'
provider:
environment:
DYNAMODB_REGION: ${aws:region}
DYNAMODB_TABLE: ${self:service}-users-${sls:stage}
iam:
role:
statements:
- Effect: 'Allow'
Action:
- 'dynamodb:CreateTable'
- 'dynamodb:PutItem'
- 'dynamodb:Get*'
- 'dynamodb:Scan*'
- 'dynamodb:UpdateItem'
- 'dynamodb:DeleteItem'
Resource: arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:service}-users-${sls:stage}
name: aws
region: ap-south-1
runtime: nodejs16.x
stage: dev
functions:
handler:
handler: index.handler
events:
- alexaSkill: amzn1.ask.skill.${param:alexaSkillId}
The org is missing in the configuration, we can specify that while deploying. We have also given permissions for the lambda function on DynamoDB incuding the create table permission, so that the lambda function can create the table if it doesn’t exist.
Deploy
Let’s deploy the function, for which first login to serverless.
$ serverless login
? Which would you like to log into? Serverless Framework Dashboard
Logging into the Serverless Dashboard via the browser
If your browser does not open automatically, please open this URL:
https://app.serverless.com?client=cli&transactionId=<some-id>
Once logged in via the browser, you should see this screen.
That’s it, time to deploy.
$ serverless deploy --org <your-org> --param="alexaSkillId=<id>"
You have to mention your org and alexaSkillId before running the command above. The org name is something you created in serverless while signing up the account, and you can get the skill ID from the alexa developer console, so that it gets mapped with alexaSkill: ${param:alexaSkillId}
in serverless.yml
The function should get successfully deployed by now. The serverless dashboard should show a successful status with green color.
Endpoints
You can get the lambda endpoint straight from the Serverless CLI.
$ serverless info --param="alexaSkillId=<your-skill-id>" --verbose
service: space-events-trivia
stage: dev
region: ap-south-1
stack: space-events-trivia-dev
functions:
handler: space-events-trivia-dev-handler
Stack Outputs:
HandlerLambdaFunctionQualifiedArn: <lambda-arn>
EnterpriseLogAccessIamRole: <role-name>
ServerlessDeploymentBucketName: <bucket-name>
Want to ditch CloudWatch? Try our new console: run "serverless --console"
You can copy the lambda ARN from the output above except the suffix which is a number, and set it as an endpoint in the Skill settings in Alexa developer console. It should have the format arn:aws:lambda:<region>:<account-id>:function:<function-name>
. I’ve just added it for the default region.
The skill could now be tested from the test window.
You can also test :test_tube: the skill from an Alexa device that’s using the same account as your developer account.
Alright then, that’s it for now, thanks for reading !!!
Image credit: unsplash