diff --git a/docs/providers/aws/events/sns.md b/docs/providers/aws/events/sns.md index a2b8689b3..3481150fa 100644 --- a/docs/providers/aws/events/sns.md +++ b/docs/providers/aws/events/sns.md @@ -50,6 +50,27 @@ functions: - sns: arn:xxx ``` +Or with intrinsic CloudFormation function like `Fn::Join` or `Fn::GetAtt`. + +```yml +functions: + dispatcher: + handler: dispatcher.dispatch + events: + - sns: + arn: + Fn::Join: + - "" + - - "arn:aws:sns:" + - Ref: "AWS::Region" + - ":" + - Ref: "AWS::AccountId" + - ":MyCustomTopic" + topicName: MyCustomTopic +``` + +**Note:** It is important to know that `topicArn` must contain the value given in the `topicName` property. + ## Setting a display name This event definition ensures that the `aggregator` function gets called every time a message is sent to the diff --git a/lib/plugins/aws/package/compile/events/sns/index.js b/lib/plugins/aws/package/compile/events/sns/index.js index 32cb99bb2..1fcba97d2 100644 --- a/lib/plugins/aws/package/compile/events/sns/index.js +++ b/lib/plugins/aws/package/compile/events/sns/index.js @@ -26,22 +26,55 @@ class AwsCompileSNSEvents { let displayName = ''; if (typeof event.sns === 'object') { - ['topicName', 'displayName'].forEach((property) => { - if (typeof event.sns[property] === 'string') { - return; + if (event.sns.arn) { + if (typeof event.sns.arn === 'object' || + typeof event.sns.arn === 'string') { + if (event.sns.topicName && typeof event.sns.topicName === 'string') { + topicArn = event.sns.arn; + topicName = event.sns.topicName; + } else { + const errorMessage = [ + 'Missing or invalid topicName property for sns event', + ` in function "${functionName}"`, + ' The correct syntax is: sns: topic-name-or-arn', + ' OR an object with ', + ' arn and topicName OR', + ' topicName and displayName.', + ' Please check the docs for more info.', + ].join(''); + throw new this.serverless.classes + .Error(errorMessage); + } + } else { + const errorMessage = [ + 'Invalid value type provided .arn property for sns event', + ` in function ${functionName}`, + ' The correct types are: object, string.', + ' Please check the docs for more info.', + ].join(''); + throw new this.serverless.classes + .Error(errorMessage); } - const errorMessage = [ - `Missing or invalid "${property}" property for sns event`, - ` in function ${functionName}`, - ' The correct syntax is: sns: topic-name-or-arn', - ' OR an object with "topicName" AND "displayName" strings.', - ' Please check the docs for more info.', - ].join(''); - throw new this.serverless.classes - .Error(errorMessage); - }); - topicName = event.sns.topicName; - displayName = event.sns.displayName; + } else { + ['topicName', 'displayName'].forEach((property) => { + if (typeof event.sns[property] === 'string') { + return; + } + const errorMessage = [ + 'Missing or invalid topicName property for sns event', + ` in function "${functionName}"`, + ' The correct syntax is: sns: topic-name-or-arn', + ' OR an object with ', + ' arn and topicName OR', + ' topicName and displayName.', + ' Please check the docs for more info.', + ].join(''); + throw new this.serverless.classes + .Error(errorMessage); + }); + displayName = event.sns.displayName; + topicName = event.sns.topicName; + } } else if (typeof event.sns === 'string') { if (event.sns.indexOf('arn:') === 0) { topicArn = event.sns; diff --git a/lib/plugins/aws/package/compile/events/sns/index.test.js b/lib/plugins/aws/package/compile/events/sns/index.test.js index ec0c50e2e..d59af889e 100644 --- a/lib/plugins/aws/package/compile/events/sns/index.test.js +++ b/lib/plugins/aws/package/compile/events/sns/index.test.js @@ -157,5 +157,48 @@ describe('AwsCompileSNSEvents', () => { .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionFooSNS.Type ).to.equal('AWS::Lambda::Permission'); }); + + it('should raise an error when only arn is present', () => { + awsCompileSNSEvents.serverless.service.functions = { + first: { + events: [ + { + sns: { + arn: 'arn:aws:sns:region:accountid:bar', + }, + }, + ], + }, + }; + + expect(() => { awsCompileSNSEvents.compileSNSEvents(); }).to.throw(Error); + }); + + it('should not create SNS topic when arn is provided', () => { + awsCompileSNSEvents.serverless.service.functions = { + first: { + events: [ + { + sns: { + topicName: 'bar', + arn: 'arn:aws:sns:region:accountid:bar', + }, + }, + ], + }, + }; + + awsCompileSNSEvents.compileSNSEvents(); + + expect(Object.keys(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources) + ).to.have.length(2); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources.FirstSnsSubscriptionBar.Type + ).to.equal('AWS::SNS::Subscription'); + expect(awsCompileSNSEvents.serverless.service + .provider.compiledCloudFormationTemplate.Resources.FirstLambdaPermissionBarSNS.Type + ).to.equal('AWS::Lambda::Permission'); + }); }); });