Skip to content

Commit c43f35f

Browse files
pubsub: privatize createTopic + default autoCreate:true
1 parent 9a49b79 commit c43f35f

File tree

7 files changed

+268
-157
lines changed

7 files changed

+268
-157
lines changed

README.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,7 @@ var pubsub = gcloud.pubsub({
213213
keyFilename: '/path/to/keyfile.json'
214214
});
215215

216-
// Create a new topic.
217-
pubsub.createTopic('my-new-topic', function(err, topic) {});
218-
219-
// Reference an existing topic.
220-
var topic = pubsub.topic('my-existing-topic');
216+
var topic = pubsub.topic('my-topic');
221217

222218
// Publish a message to the topic.
223219
topic.publish({

lib/pubsub/index.js

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -148,34 +148,6 @@ PubSub.prototype.getTopics = function(query, callback) {
148148
});
149149
};
150150

151-
/**
152-
* Create a topic with the given name.
153-
*
154-
* @param {string} name - Name of the topic.
155-
* @param {function=} callback - The callback function.
156-
* @param {?error} callback.err - An error from the API call, may be null.
157-
* @param {module:pubsub/topic} callback.topic - The newly created topic.
158-
* @param {object} callback.apiResponse - The full API response from the
159-
* service.
160-
*
161-
* @example
162-
* pubsub.createTopic('my-new-topic', function(err, topic, apiResponse) {
163-
* topic.publish('New message!', function(err) {});
164-
* });
165-
*/
166-
PubSub.prototype.createTopic = function(name, callback) {
167-
callback = callback || util.noop;
168-
var topic = this.topic(name);
169-
var path = this.projectName + '/topics/' + name;
170-
this.makeReq_('PUT', path, null, null, function(err, result) {
171-
if (err) {
172-
callback(err, null, result);
173-
return;
174-
}
175-
callback(null, topic, result);
176-
});
177-
};
178-
179151
/**
180152
* Create a subscription to a topic. You may optionally provide an object to
181153
* customize the subscription.
@@ -315,14 +287,13 @@ PubSub.prototype.subscription = function(name, options) {
315287
*
316288
* @param {string} name - The name of the topic.
317289
* @param {object=} options - Configuration object.
318-
* @param {boolean=} options.autoCreate - Automatically create topic if it
290+
* @param {boolean} options.autoCreate - Automatically create topic if it
319291
* doesn't exist. Note that messages published to a topic with no
320-
* subscribers will not be delivered.
292+
* subscribers will not be delivered. Default: true.
321293
* @return {module:pubsub/topic}
322294
*
323295
* @example
324-
* var topic = pubsub.topic('my-existing-topic');
325-
* var topic = pubsub.topic('topic-that-maybe-exists', { autoCreate: true });
296+
* var topic = pubsub.topic('my-topic');
326297
*/
327298
PubSub.prototype.topic = function(name, options) {
328299
if (!name) {
@@ -436,6 +407,36 @@ PubSub.prototype.getSubscriptions = function(options, callback) {
436407
});
437408
};
438409

410+
/**
411+
* Create a topic with the given name.
412+
*
413+
* @private
414+
*
415+
* @param {string} name - Name of the topic.
416+
* @param {function=} callback - The callback function.
417+
* @param {?error} callback.err - An error from the API call, may be null.
418+
* @param {module:pubsub/topic} callback.topic - The newly created topic.
419+
* @param {object} callback.apiResponse - The full API response from the
420+
* service.
421+
*
422+
* @example
423+
* pubsub.createTopic_('my-new-topic', function(err, topic, apiResponse) {
424+
* topic.publish('New message!', function(err) {});
425+
* });
426+
*/
427+
PubSub.prototype.createTopic_ = function(name, callback) {
428+
callback = callback || util.noop;
429+
var topic = this.topic(name);
430+
var path = this.projectName + '/topics/' + name;
431+
this.makeReq_('PUT', path, null, null, function(err, result) {
432+
if (err) {
433+
callback(err, null, result);
434+
return;
435+
}
436+
callback(null, topic, result);
437+
});
438+
};
439+
439440
/**
440441
* Make a new request object from the provided arguments and wrap the callback
441442
* to intercept non-successful responses.

lib/pubsub/subscription.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,23 +76,23 @@ var util = require('../common/util.js');
7676
* //-
7777
* // From {@linkcode module:pubsub/topic#getSubscriptions}:
7878
* //-
79-
* var topic = pubsub.topic('my-existing-topic');
79+
* var topic = pubsub.topic('my-topic');
8080
* topic.getSubscriptions(function(err, subscriptions) {
8181
* // `subscriptions` is an array of Subscription objects.
8282
* });
8383
*
8484
* //-
8585
* // From {@linkcode module:pubsub/topic#subscribe}:
8686
* //-
87-
* var topic = pubsub.topic('my-existing-topic');
87+
* var topic = pubsub.topic('my-topic');
8888
* topic.subscribe('new-subscription', function(err, subscription) {
8989
* // `subscription` is a Subscription object.
9090
* });
9191
*
9292
* //-
9393
* // From {@linkcode module:pubsub/topic#subscription}:
9494
* //-
95-
* var topic = pubsub.topic('my-existing-topic');
95+
* var topic = pubsub.topic('my-topic');
9696
* var subscription = topic.subscription('my-existing-subscription');
9797
* // `subscription` is a Subscription object.
9898
*

lib/pubsub/topic.js

Lines changed: 45 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@ var util = require('../common/util.js');
3030
*
3131
* @param {module:pubsub} pubsub - PubSub object.
3232
* @param {object} options - Configuration object.
33+
* @param {boolean=} options.autoCreate - Automatically create topic if it
34+
* doesn't exist. Note that messages published to a topic with no
35+
* subscribers will not be delivered. Default: true.
3336
* @param {string} options.name - Name of the topic.
3437
*/
3538
/**
36-
* A Topic object allows you to interact with a Google Cloud Pub/Sub topic. To
37-
* get this object, you will use the methods on the `pubsub` object,
38-
* {@linkcode module:pubsub#topic} and {@linkcode module:pubsub#createTopic}.
39+
* A Topic object allows you to interact with a Google Cloud Pub/Sub topic.
3940
*
4041
* @constructor
4142
* @alias module:pubsub/topic
@@ -45,25 +46,15 @@ var util = require('../common/util.js');
4546
* projectId: 'grape-spaceship-123'
4647
* });
4748
*
48-
* // From pubsub.topic:
49-
* var topic = pubsub.topic('my-existing-topic');
50-
*
51-
* // From pubsub.createTopic:
52-
* pubsub.createTopic('my-new-topic', function(err, topic) {
53-
* // `topic` is a Topic object.
54-
* });
49+
* var topic = pubsub.topic('my-topic');
5550
*/
5651
function Topic(pubsub, options) {
57-
this.makeReq_ = pubsub.makeReq_.bind(pubsub);
52+
this.autoCreate = options.autoCreate !== false;
5853
this.name = Topic.formatName_(pubsub.projectId, options.name);
54+
5955
this.projectId = pubsub.projectId;
6056
this.pubsub = pubsub;
6157
this.unformattedName = options.name;
62-
63-
if (options.autoCreate) {
64-
this.origMakeReq_ = this.makeReq_;
65-
this.makeReq_ = this.autoCreateWrapper_;
66-
}
6758
}
6859

6960
/**
@@ -99,34 +90,6 @@ Topic.formatName_ = function(projectId, name) {
9990
return 'projects/' + projectId + '/topics/' + name;
10091
};
10192

102-
/**
103-
* Wrapper for makeReq_ that automatically attempts to create a topic if it does
104-
* not yet exist.
105-
*
106-
* @private
107-
*/
108-
Topic.prototype.autoCreateWrapper_ = function(method, path, q, body, callback) {
109-
var self = this;
110-
111-
function createAndRetry() {
112-
self.pubsub.createTopic(self.unformattedName, function(err) {
113-
if (err) {
114-
callback(err);
115-
return;
116-
}
117-
self.origMakeReq_(method, path, q, body, callback);
118-
});
119-
}
120-
121-
this.origMakeReq_(method, path, q, body, function(err, res) {
122-
if (err && err.code === 404 && method !== 'DELETE') {
123-
createAndRetry();
124-
} else {
125-
callback(err, res);
126-
}
127-
});
128-
};
129-
13093
/**
13194
* Publish the provided message or array of messages. On success, an array of
13295
* messageIds is returned in the response.
@@ -144,7 +107,7 @@ Topic.prototype.autoCreateWrapper_ = function(method, path, q, body, callback) {
144107
* topic.publish({
145108
* data: 'Hello, world!'
146109
* }, function(err, messageIds, apiResponse) {});
147-
*
110+
*
148111
* //-
149112
* // The data property can be a JSON object as well.
150113
* //-
@@ -159,7 +122,7 @@ Topic.prototype.autoCreateWrapper_ = function(method, path, q, body, callback) {
159122
* hello: 'world'
160123
* }
161124
* };
162-
*
125+
*
163126
* topic.publish(registerMessage, function(err, messageIds, apiResponse) {});
164127
*
165128
* //-
@@ -321,4 +284,40 @@ Topic.prototype.subscription = function(name, options) {
321284
return this.pubsub.subscription(name, options);
322285
};
323286

287+
/**
288+
* Make an API request using the parent PubSub object's `makeReq_`. If the Topic
289+
* instance has `autoCreate: true` set, this method will first try to create the
290+
* Topic in the event of a 404.
291+
*
292+
* @private
293+
*
294+
* @param {string} method - Action.
295+
* @param {string} path - Request path.
296+
* @param {*} query - Request query object.
297+
* @param {*} body - Request body contents.
298+
* @param {function} callback - The callback function.
299+
*/
300+
Topic.prototype.makeReq_ = function(method, path, query, body, callback) {
301+
var self = this;
302+
303+
function createTopicThenRetryRequest() {
304+
self.pubsub.createTopic_(self.unformattedName, function(err, topic, res) {
305+
if (err) {
306+
callback(err, null, res);
307+
return;
308+
}
309+
310+
self.pubsub.makeReq_(method, path, query, body, callback);
311+
});
312+
}
313+
314+
this.pubsub.makeReq_(method, path, query, body, function(err, res) {
315+
if (self.autoCreate && err && err.code === 404 && method !== 'DELETE') {
316+
createTopicThenRetryRequest();
317+
} else {
318+
callback(err, res);
319+
}
320+
});
321+
};
322+
324323
module.exports = Topic;

system-test/pubsub.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe('pubsub', function() {
5151
before(function(done) {
5252
// create all needed topics
5353
async.each(TOPIC_NAMES, function(name, cb) {
54-
pubsub.createTopic(name, cb);
54+
pubsub.createTopic_(name, cb);
5555
}, done);
5656
});
5757

@@ -63,7 +63,6 @@ describe('pubsub', function() {
6363
});
6464

6565
describe('Topic', function() {
66-
6766
it('should be listed', function(done) {
6867
pubsub.getTopics(function(err, topics) {
6968
assert.ifError(err);
@@ -92,12 +91,31 @@ describe('pubsub', function() {
9291

9392
it('should be created and deleted', function(done) {
9493
var TOPIC_NAME = generateTopicName();
95-
pubsub.createTopic(TOPIC_NAME, function(err) {
94+
pubsub.createTopic_(TOPIC_NAME, function(err) {
9695
assert.ifError(err);
9796
pubsub.topic(TOPIC_NAME).delete(done);
9897
});
9998
});
10099

100+
it('should lazily create by default', function(done) {
101+
var newTopicName = generateTopicName();
102+
var newTopic = pubsub.topic(newTopicName);
103+
104+
newTopic.publish({ data: 'message from me' }, function(err) {
105+
assert.ifError(err);
106+
107+
pubsub.getTopics(function(err, topics) {
108+
assert.ifError(err);
109+
110+
assert(topics.some(function(topic) {
111+
return topic.name.indexOf(newTopicName) > -1;
112+
}));
113+
114+
newTopic.delete(done);
115+
});
116+
});
117+
});
118+
101119
it('should publish a message', function(done) {
102120
var topic = pubsub.topic(TOPIC_NAMES[0]);
103121
topic.publish({ data: 'message from me' }, function(err, messageIds) {
@@ -131,7 +149,7 @@ describe('pubsub', function() {
131149

132150
before(function(done) {
133151
// Create a new test topic.
134-
pubsub.createTopic(TOPIC_NAME, function(err, newTopic) {
152+
pubsub.createTopic_(TOPIC_NAME, function(err, newTopic) {
135153
assert.ifError(err);
136154
topic = newTopic;
137155

0 commit comments

Comments
 (0)