Skip to content

Commit

Permalink
feat(sns): Support raw message delivery (#1827)
Browse files Browse the repository at this point in the history
Adds a handler to enable raw message delivery on SNS topic subscriptions.
  • Loading branch information
RomainMuller authored Feb 21, 2019
1 parent 1060b95 commit cc0a28c
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 10 deletions.
16 changes: 15 additions & 1 deletion packages/@aws-cdk/aws-sns/lib/subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ export interface SubscriptionProps {
* The topic to subscribe to.
*/
topic: ITopic;

/**
* true if raw message delivery is enabled for the subscription. Raw messages are free of JSON formatting and can be
* sent to HTTP/S and Amazon SQS endpoints. For more information, see GetSubscriptionAttributes in the Amazon Simple
* Notification Service API Reference.
*
* @default false
*/
rawMessageDelivery?: boolean;
}

/**
Expand All @@ -34,10 +43,15 @@ export class Subscription extends Construct {
constructor(scope: Construct, id: string, props: SubscriptionProps) {
super(scope, id);

if (props.rawMessageDelivery && ['http', 'https', 'sqs'].indexOf(props.protocol) < 0) {
throw new Error('Raw message delivery can only be enabled for HTTP/S and SQS subscriptions.');
}

new CfnSubscription(this, 'Resource', {
endpoint: props.endpoint,
protocol: props.protocol,
topicArn: props.topic.topicArn
topicArn: props.topic.topicArn,
rawMessageDelivery: props.rawMessageDelivery,
});

}
Expand Down
23 changes: 14 additions & 9 deletions packages/@aws-cdk/aws-sns/lib/topic-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,12 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
/**
* Subscribe some endpoint to this topic
*/
public subscribe(name: string, endpoint: string, protocol: SubscriptionProtocol): Subscription {
public subscribe(name: string, endpoint: string, protocol: SubscriptionProtocol, rawMessageDelivery?: boolean): Subscription {
return new Subscription(this, name, {
topic: this,
endpoint,
protocol
protocol,
rawMessageDelivery,
});
}

Expand All @@ -134,8 +135,9 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
*
* @param name The subscription name
* @param queue The target queue
* @param rawMessageDelivery Enable raw message delivery
*/
public subscribeQueue(queue: sqs.IQueue): Subscription {
public subscribeQueue(queue: sqs.IQueue, rawMessageDelivery?: boolean): Subscription {
if (!cdk.Construct.isConstruct(queue)) {
throw new Error(`The supplied Queue object must be an instance of Construct`);
}
Expand All @@ -151,7 +153,8 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
const sub = new Subscription(queue, subscriptionName, {
topic: this,
endpoint: queue.queueArn,
protocol: SubscriptionProtocol.Sqs
protocol: SubscriptionProtocol.Sqs,
rawMessageDelivery,
});

// add a statement to the queue resource policy which allows this topic
Expand Down Expand Up @@ -190,7 +193,7 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
const sub = new Subscription(lambdaFunction, subscriptionName, {
topic: this,
endpoint: lambdaFunction.functionArn,
protocol: SubscriptionProtocol.Lambda
protocol: SubscriptionProtocol.Lambda,
});

lambdaFunction.addPermission(this.node.id, {
Expand All @@ -206,7 +209,7 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
*
* @param name A name for the subscription
* @param emailAddress The email address to use.
* @param jsonFormat True if the email content should be in JSON format (default is false).
* @param options Options for the email delivery format.
*/
public subscribeEmail(name: string, emailAddress: string, options?: EmailSubscriptionOptions): Subscription {
const protocol = (options && options.json ? SubscriptionProtocol.EmailJson : SubscriptionProtocol.Email);
Expand All @@ -223,8 +226,9 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
*
* @param name A name for the subscription
* @param url The URL to invoke
* @param rawMessageDelivery Enable raw message delivery
*/
public subscribeUrl(name: string, url: string): Subscription {
public subscribeUrl(name: string, url: string, rawMessageDelivery?: boolean): Subscription {
if (!url.startsWith('http://') && !url.startsWith('https://')) {
throw new Error('URL must start with either http:// or https://');
}
Expand All @@ -234,7 +238,8 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
return new Subscription(this, name, {
topic: this,
endpoint: url,
protocol
protocol,
rawMessageDelivery,
});
}

Expand Down Expand Up @@ -353,5 +358,5 @@ export interface EmailSubscriptionOptions {
*
* @default Message text (false)
*/
json?: boolean
json?: boolean;
}
74 changes: 74 additions & 0 deletions packages/@aws-cdk/aws-sns/test/test.sns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,40 @@ export = {
test.done();
},

'url subscription (with raw delivery)'(test: Test) {
const stack = new cdk.Stack();

const topic = new sns.Topic(stack, 'MyTopic', {
topicName: 'topicName',
displayName: 'displayName'
});

topic.subscribeUrl('appsubscription', 'https://foobar.com/', true);

expect(stack).toMatch({
"Resources": {
"MyTopic86869434": {
"Type": "AWS::SNS::Topic",
"Properties": {
"DisplayName": "displayName",
"TopicName": "topicName"
}
},
"MyTopicappsubscription00FA69EA": {
"Type": "AWS::SNS::Subscription",
"Properties": {
"Endpoint": "https://foobar.com/",
"Protocol": "https",
"TopicArn": { "Ref": "MyTopic86869434" },
"RawMessageDelivery": true
}
}
}
});

test.done();
},

'queue subscription'(test: Test) {
const stack = new cdk.Stack();

Expand Down Expand Up @@ -208,6 +242,35 @@ export = {
test.done();
},

'queue subscription (with raw delivery)'(test: Test) {
const stack = new cdk.Stack();

const topic = new sns.Topic(stack, 'MyTopic', {
topicName: 'topicName',
displayName: 'displayName'
});

const queue = new sqs.Queue(stack, 'MyQueue');

topic.subscribeQueue(queue, true);

expect(stack).to(haveResource('AWS::SNS::Subscription', {
"Endpoint": {
"Fn::GetAtt": [
"MyQueueE6CA6235",
"Arn"
]
},
"Protocol": "sqs",
"TopicArn": {
"Ref": "MyTopic86869434"
},
"RawMessageDelivery": true
}));

test.done();
},

'lambda subscription'(test: Test) {
const stack = new cdk.Stack();

Expand Down Expand Up @@ -504,6 +567,17 @@ export = {

test.done();
},

'invalid use of raw message delivery'(test: Test) {
// GIVEN
const stack = new cdk.Stack();
const topic = new sns.Topic(stack, 'Topic');

// THEN
test.throws(() => topic.subscribe('Nope', 'endpoint://location', sns.SubscriptionProtocol.Application, true),
/Raw message delivery can only be enabled for HTTP\/S and SQS subscriptions/);
test.done();
}
},

'can add a policy to the topic'(test: Test) {
Expand Down

0 comments on commit cc0a28c

Please sign in to comment.