Skip to content

Commit cc0a28c

Browse files
authored
feat(sns): Support raw message delivery (#1827)
Adds a handler to enable raw message delivery on SNS topic subscriptions.
1 parent 1060b95 commit cc0a28c

File tree

3 files changed

+103
-10
lines changed

3 files changed

+103
-10
lines changed

packages/@aws-cdk/aws-sns/lib/subscription.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ export interface SubscriptionProps {
2222
* The topic to subscribe to.
2323
*/
2424
topic: ITopic;
25+
26+
/**
27+
* true if raw message delivery is enabled for the subscription. Raw messages are free of JSON formatting and can be
28+
* sent to HTTP/S and Amazon SQS endpoints. For more information, see GetSubscriptionAttributes in the Amazon Simple
29+
* Notification Service API Reference.
30+
*
31+
* @default false
32+
*/
33+
rawMessageDelivery?: boolean;
2534
}
2635

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

46+
if (props.rawMessageDelivery && ['http', 'https', 'sqs'].indexOf(props.protocol) < 0) {
47+
throw new Error('Raw message delivery can only be enabled for HTTP/S and SQS subscriptions.');
48+
}
49+
3750
new CfnSubscription(this, 'Resource', {
3851
endpoint: props.endpoint,
3952
protocol: props.protocol,
40-
topicArn: props.topic.topicArn
53+
topicArn: props.topic.topicArn,
54+
rawMessageDelivery: props.rawMessageDelivery,
4155
});
4256

4357
}

packages/@aws-cdk/aws-sns/lib/topic-base.ts

+14-9
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,12 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
118118
/**
119119
* Subscribe some endpoint to this topic
120120
*/
121-
public subscribe(name: string, endpoint: string, protocol: SubscriptionProtocol): Subscription {
121+
public subscribe(name: string, endpoint: string, protocol: SubscriptionProtocol, rawMessageDelivery?: boolean): Subscription {
122122
return new Subscription(this, name, {
123123
topic: this,
124124
endpoint,
125-
protocol
125+
protocol,
126+
rawMessageDelivery,
126127
});
127128
}
128129

@@ -134,8 +135,9 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
134135
*
135136
* @param name The subscription name
136137
* @param queue The target queue
138+
* @param rawMessageDelivery Enable raw message delivery
137139
*/
138-
public subscribeQueue(queue: sqs.IQueue): Subscription {
140+
public subscribeQueue(queue: sqs.IQueue, rawMessageDelivery?: boolean): Subscription {
139141
if (!cdk.Construct.isConstruct(queue)) {
140142
throw new Error(`The supplied Queue object must be an instance of Construct`);
141143
}
@@ -151,7 +153,8 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
151153
const sub = new Subscription(queue, subscriptionName, {
152154
topic: this,
153155
endpoint: queue.queueArn,
154-
protocol: SubscriptionProtocol.Sqs
156+
protocol: SubscriptionProtocol.Sqs,
157+
rawMessageDelivery,
155158
});
156159

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

196199
lambdaFunction.addPermission(this.node.id, {
@@ -206,7 +209,7 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
206209
*
207210
* @param name A name for the subscription
208211
* @param emailAddress The email address to use.
209-
* @param jsonFormat True if the email content should be in JSON format (default is false).
212+
* @param options Options for the email delivery format.
210213
*/
211214
public subscribeEmail(name: string, emailAddress: string, options?: EmailSubscriptionOptions): Subscription {
212215
const protocol = (options && options.json ? SubscriptionProtocol.EmailJson : SubscriptionProtocol.Email);
@@ -223,8 +226,9 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
223226
*
224227
* @param name A name for the subscription
225228
* @param url The URL to invoke
229+
* @param rawMessageDelivery Enable raw message delivery
226230
*/
227-
public subscribeUrl(name: string, url: string): Subscription {
231+
public subscribeUrl(name: string, url: string, rawMessageDelivery?: boolean): Subscription {
228232
if (!url.startsWith('http://') && !url.startsWith('https://')) {
229233
throw new Error('URL must start with either http:// or https://');
230234
}
@@ -234,7 +238,8 @@ export abstract class TopicBase extends cdk.Construct implements ITopic {
234238
return new Subscription(this, name, {
235239
topic: this,
236240
endpoint: url,
237-
protocol
241+
protocol,
242+
rawMessageDelivery,
238243
});
239244
}
240245

@@ -353,5 +358,5 @@ export interface EmailSubscriptionOptions {
353358
*
354359
* @default Message text (false)
355360
*/
356-
json?: boolean
361+
json?: boolean;
357362
}

packages/@aws-cdk/aws-sns/test/test.sns.ts

+74
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,40 @@ export = {
128128
test.done();
129129
},
130130

131+
'url subscription (with raw delivery)'(test: Test) {
132+
const stack = new cdk.Stack();
133+
134+
const topic = new sns.Topic(stack, 'MyTopic', {
135+
topicName: 'topicName',
136+
displayName: 'displayName'
137+
});
138+
139+
topic.subscribeUrl('appsubscription', 'https://foobar.com/', true);
140+
141+
expect(stack).toMatch({
142+
"Resources": {
143+
"MyTopic86869434": {
144+
"Type": "AWS::SNS::Topic",
145+
"Properties": {
146+
"DisplayName": "displayName",
147+
"TopicName": "topicName"
148+
}
149+
},
150+
"MyTopicappsubscription00FA69EA": {
151+
"Type": "AWS::SNS::Subscription",
152+
"Properties": {
153+
"Endpoint": "https://foobar.com/",
154+
"Protocol": "https",
155+
"TopicArn": { "Ref": "MyTopic86869434" },
156+
"RawMessageDelivery": true
157+
}
158+
}
159+
}
160+
});
161+
162+
test.done();
163+
},
164+
131165
'queue subscription'(test: Test) {
132166
const stack = new cdk.Stack();
133167

@@ -208,6 +242,35 @@ export = {
208242
test.done();
209243
},
210244

245+
'queue subscription (with raw delivery)'(test: Test) {
246+
const stack = new cdk.Stack();
247+
248+
const topic = new sns.Topic(stack, 'MyTopic', {
249+
topicName: 'topicName',
250+
displayName: 'displayName'
251+
});
252+
253+
const queue = new sqs.Queue(stack, 'MyQueue');
254+
255+
topic.subscribeQueue(queue, true);
256+
257+
expect(stack).to(haveResource('AWS::SNS::Subscription', {
258+
"Endpoint": {
259+
"Fn::GetAtt": [
260+
"MyQueueE6CA6235",
261+
"Arn"
262+
]
263+
},
264+
"Protocol": "sqs",
265+
"TopicArn": {
266+
"Ref": "MyTopic86869434"
267+
},
268+
"RawMessageDelivery": true
269+
}));
270+
271+
test.done();
272+
},
273+
211274
'lambda subscription'(test: Test) {
212275
const stack = new cdk.Stack();
213276

@@ -504,6 +567,17 @@ export = {
504567

505568
test.done();
506569
},
570+
571+
'invalid use of raw message delivery'(test: Test) {
572+
// GIVEN
573+
const stack = new cdk.Stack();
574+
const topic = new sns.Topic(stack, 'Topic');
575+
576+
// THEN
577+
test.throws(() => topic.subscribe('Nope', 'endpoint://location', sns.SubscriptionProtocol.Application, true),
578+
/Raw message delivery can only be enabled for HTTP\/S and SQS subscriptions/);
579+
test.done();
580+
}
507581
},
508582

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

0 commit comments

Comments
 (0)