mirror of
https://github.com/serverless/serverless.git
synced 2026-01-18 14:58:43 +00:00
Add alexa event source
Based on the great PR and plugin by @rajington 🙌
This commit is contained in:
parent
4ffa47f6cb
commit
b5ddec70e2
@ -79,6 +79,7 @@ The Serverless Framework allows you to deploy auto-scaling, pay-per-execution, e
|
||||
<li><a href="./providers/aws/events/s3.md">S3</a></li>
|
||||
<li><a href="./providers/aws/events/schedule.md">Schedule</a></li>
|
||||
<li><a href="./providers/aws/events/sns.md">SNS</a></li>
|
||||
<li><a href="./providers/aws/events/alexa.md">Alexa</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
25
docs/providers/aws/events/alexa.md
Normal file
25
docs/providers/aws/events/alexa.md
Normal file
@ -0,0 +1,25 @@
|
||||
<!--
|
||||
title: Serverless Framework - AWS Lambda Events - Alexa
|
||||
menuText: Alexa
|
||||
menuOrder: 6
|
||||
description: Setting up AWS Alexa Events with AWS Lambda via the Serverless Framework
|
||||
layout: Doc
|
||||
-->
|
||||
|
||||
<!-- DOCS-SITE-LINK:START automatically generated -->
|
||||
### [Read this on the main serverless docs site](https://www.serverless.com/framework/docs/providers/aws/events/alexa)
|
||||
<!-- DOCS-SITE-LINK:END -->
|
||||
|
||||
# Alexa
|
||||
|
||||
## Event definition
|
||||
|
||||
This will enable your Lambda function to be called by an Alexa skill kit.
|
||||
|
||||
```yaml
|
||||
functions:
|
||||
mySkill:
|
||||
handler: mySkill.handler
|
||||
events:
|
||||
- alexa: true
|
||||
```
|
||||
@ -71,7 +71,7 @@ We're also using the term `normalizedName` or similar terms in this guide. This
|
||||
|Lambda::Function | {normalizedFunctionName}LambdaFunction | HelloLambdaFunction |
|
||||
|Lambda::Version | {normalizedFunctionName}LambdaVersion{sha256} | HelloLambdaVersionr3pgoTvv1xT4E4NiCL6JG02fl6vIyi7OS1aW0FwAI |
|
||||
|Logs::LogGroup | {normalizedFunctionName}LogGroup | HelloLogGroup |
|
||||
|Lambda::Permission | <ul><li>**Schedule**: {normalizedFunctionName}LambdaPermissionEventsRuleSchedule{index} </li><li>**S3**: {normalizedFunctionName}LambdaPermission{normalizedBucketName}S3</li><li>**APIG**: {normalizedFunctionName}LambdaPermissionApiGateway</li><li>**SNS**: {normalizedFunctionName}LambdaPermission{normalizedTopicName}SNS</li> | <ul><li>**Schedule**: HelloLambdaPermissionEventsRuleSchedule1 </li><li>**S3**: HelloLambdaPermissionBucketS3</li><li>**APIG**: HelloLambdaPermissionApiGateway</li><li>**SNS**: HelloLambdaPermissionTopicSNS</li> |
|
||||
|Lambda::Permission | <ul><li>**Schedule**: {normalizedFunctionName}LambdaPermissionEventsRuleSchedule{index}</li><li>**S3**: {normalizedFunctionName}LambdaPermission{normalizedBucketName}S3</li><li>**APIG**: {normalizedFunctionName}LambdaPermissionApiGateway</li><li>**SNS**: {normalizedFunctionName}LambdaPermission{normalizedTopicName}SNS</li><li>**Alexa**: {normalizedFunctionName}LambdaPermissionAlexa</li> </ul> | <ul><li>**Schedule**: HelloLambdaPermissionEventsRuleSchedule1</li><li>**S3**: HelloLambdaPermissionBucketS3</li><li>**APIG**: HelloLambdaPermissionApiGateway</li><li>**SNS**: HelloLambdaPermissionTopicSNS</li><li>**Alexa**: HelloLambdaPermissionAlexa</li> </ul>|
|
||||
|Events::Rule | {normalizedFuntionName}EventsRuleSchedule{SequentialID} | HelloEventsRuleSchedule1 |
|
||||
|ApiGateway::RestApi | ApiGatewayRestApi | ApiGatewayRestApi |
|
||||
|ApiGateway::Resource | ApiGatewayResource{normalizedPath} | ApiGatewayResourceUsers |
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
"./aws/deploy/compile/events/apiGateway/index.js",
|
||||
"./aws/deploy/compile/events/sns/index.js",
|
||||
"./aws/deploy/compile/events/stream/index.js",
|
||||
"./aws/deploy/compile/events/alexa/index.js",
|
||||
"./aws/deployFunction/index.js",
|
||||
"./aws/deployList/index.js",
|
||||
"./aws/invokeLocal/index.js"
|
||||
|
||||
64
lib/plugins/aws/deploy/compile/events/alexa/index.js
Normal file
64
lib/plugins/aws/deploy/compile/events/alexa/index.js
Normal file
@ -0,0 +1,64 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
|
||||
class AwsCompileAlexaEvents {
|
||||
constructor(serverless) {
|
||||
this.serverless = serverless;
|
||||
this.provider = this.serverless.getProvider('aws');
|
||||
|
||||
this.hooks = {
|
||||
'deploy:compileEvents': this.compileAlexaEvents.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
compileAlexaEvents() {
|
||||
this.serverless.service.getAllFunctions().forEach((functionName) => {
|
||||
const functionObj = this.serverless.service.getFunction(functionName);
|
||||
|
||||
if (functionObj.events) {
|
||||
functionObj.events.forEach(event => {
|
||||
if (event.alexa) {
|
||||
if (typeof event.alexa === 'boolean' && event.alexa) {
|
||||
const lambdaLogicalId = this.provider.naming
|
||||
.getLambdaLogicalId(functionName);
|
||||
|
||||
const permissionTemplate = {
|
||||
Type: 'AWS::Lambda::Permission',
|
||||
Properties: {
|
||||
FunctionName: {
|
||||
'Fn::GetAtt': [
|
||||
lambdaLogicalId,
|
||||
'Arn',
|
||||
],
|
||||
},
|
||||
Action: 'lambda:InvokeFunction',
|
||||
Principal: 'alexa-appkit.amazon.com',
|
||||
},
|
||||
};
|
||||
|
||||
const lambdaPermissionLogicalId = this.provider.naming
|
||||
.getLambdaAlexaPermissionLogicalId(functionName);
|
||||
|
||||
const permissionCloudForamtionResource = {
|
||||
[lambdaPermissionLogicalId]: permissionTemplate,
|
||||
};
|
||||
|
||||
_.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources,
|
||||
permissionCloudForamtionResource);
|
||||
} else {
|
||||
const errorMessage = [
|
||||
`Alexa event of function "${functionName}" is not a boolean.`,
|
||||
' The correct syntax is: alexa: true.',
|
||||
' Please check the docs for more info.',
|
||||
].join('');
|
||||
throw new this.serverless.classes.Error(errorMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AwsCompileAlexaEvents;
|
||||
105
lib/plugins/aws/deploy/compile/events/alexa/index.test.js
Normal file
105
lib/plugins/aws/deploy/compile/events/alexa/index.test.js
Normal file
@ -0,0 +1,105 @@
|
||||
'use strict';
|
||||
|
||||
const expect = require('chai').expect;
|
||||
const AwsProvider = require('../../../../provider/awsProvider');
|
||||
const AwsCompileAlexaEvents = require('./index');
|
||||
const Serverless = require('../../../../../../Serverless');
|
||||
|
||||
describe('AwsCompileAlexaEvents', () => {
|
||||
let serverless;
|
||||
let awsCompileAlexaEvents;
|
||||
|
||||
beforeEach(() => {
|
||||
serverless = new Serverless();
|
||||
serverless.service.provider.compiledCloudFormationTemplate = { Resources: {} };
|
||||
serverless.setProvider('aws', new AwsProvider(serverless));
|
||||
awsCompileAlexaEvents = new AwsCompileAlexaEvents(serverless);
|
||||
});
|
||||
|
||||
describe('#constructor()', () => {
|
||||
it('should set the provider variable to an instance of AwsProvider', () =>
|
||||
expect(awsCompileAlexaEvents.provider).to.be.instanceof(AwsProvider));
|
||||
|
||||
it('should should hook into the "deploy:compileEvents" hook', () =>
|
||||
expect(awsCompileAlexaEvents.hooks['deploy:compileEvents']).to.not.equal(undefined));
|
||||
});
|
||||
|
||||
describe('#compileAlexaEvents()', () => {
|
||||
it('should throw an error if alexa event type is not a boolean', () => {
|
||||
awsCompileAlexaEvents.serverless.service.functions = {
|
||||
first: {
|
||||
events: [
|
||||
{
|
||||
alexa: 42,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
expect(() => awsCompileAlexaEvents.compileAlexaEvents()).to.throw(Error);
|
||||
});
|
||||
|
||||
it('should create corresponding resources when event is given with value "true"', () => {
|
||||
awsCompileAlexaEvents.serverless.service.functions = {
|
||||
first: {
|
||||
events: [
|
||||
{
|
||||
alexa: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
awsCompileAlexaEvents.compileAlexaEvents();
|
||||
|
||||
expect(awsCompileAlexaEvents.serverless.service
|
||||
.provider.compiledCloudFormationTemplate.Resources
|
||||
.FirstLambdaPermissionAlexa.Type
|
||||
).to.equal('AWS::Lambda::Permission');
|
||||
expect(awsCompileAlexaEvents.serverless.service
|
||||
.provider.compiledCloudFormationTemplate.Resources
|
||||
.FirstLambdaPermissionAlexa.Properties.FunctionName
|
||||
).to.deep.equal({ 'Fn::GetAtt': ['FirstLambdaFunction', 'Arn'] });
|
||||
expect(awsCompileAlexaEvents.serverless.service
|
||||
.provider.compiledCloudFormationTemplate.Resources
|
||||
.FirstLambdaPermissionAlexa.Properties.Action
|
||||
).to.equal('lambda:InvokeFunction');
|
||||
expect(awsCompileAlexaEvents.serverless.service
|
||||
.provider.compiledCloudFormationTemplate.Resources
|
||||
.FirstLambdaPermissionAlexa.Properties.Principal
|
||||
).to.equal('alexa-appkit.amazon.com');
|
||||
});
|
||||
|
||||
it('should not create corresponding resources when event is given with value "false"', () => {
|
||||
awsCompileAlexaEvents.serverless.service.functions = {
|
||||
first: {
|
||||
events: [
|
||||
{
|
||||
alexa: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
awsCompileAlexaEvents.compileAlexaEvents();
|
||||
|
||||
expect(
|
||||
awsCompileAlexaEvents.serverless.service.provider.compiledCloudFormationTemplate.Resources
|
||||
).to.deep.equal({});
|
||||
});
|
||||
|
||||
it('should not create corresponding resources when alexa event is not given', () => {
|
||||
awsCompileAlexaEvents.serverless.service.functions = {
|
||||
first: {
|
||||
events: [],
|
||||
},
|
||||
};
|
||||
|
||||
awsCompileAlexaEvents.compileAlexaEvents();
|
||||
|
||||
expect(
|
||||
awsCompileAlexaEvents.serverless.service.provider.compiledCloudFormationTemplate.Resources
|
||||
).to.deep.equal({});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -227,4 +227,7 @@ module.exports = {
|
||||
getLambdaApiGatewayPermissionLogicalId(functionName) {
|
||||
return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionApiGateway`;
|
||||
},
|
||||
getLambdaAlexaPermissionLogicalId(functionName) {
|
||||
return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionAlexa`;
|
||||
},
|
||||
};
|
||||
|
||||
@ -429,4 +429,12 @@ describe('#naming()', () => {
|
||||
.to.equal('FunctionNameLambdaPermissionApiGateway');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getLambdaAlexaPermissionLogicalId()', () => {
|
||||
it('should normalize the function name and append the standard suffix',
|
||||
() => {
|
||||
expect(sdk.naming.getLambdaAlexaPermissionLogicalId('functionName'))
|
||||
.to.equal('FunctionNameLambdaPermissionAlexa');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user