diff --git a/src/topic.ts b/src/topic.ts index 425db55d1..62549e890 100644 --- a/src/topic.ts +++ b/src/topic.ts @@ -522,6 +522,66 @@ export class Topic { publish(data: Buffer, attributes?, callback?): Promise|void { return this.publisher.publish(data, attributes, callback); } + /** + * Publish the provided JSON. It should be noted that all messages published + * are done so in the form of a Buffer. This is simply a convenience method + * that will transform JSON into a Buffer before publishing. + * {@link Subscription} objects will always return message data in the form of + * a Buffer, so any JSON published will require manual deserialization. + * + * @see Topic#publish + * + * @throws {Error} If non-object data is provided. + * + * @param {object} json The JSON data to publish. + * @param {object} [attributes] Attributes for this message. + * @param {PublishCallback} [callback] Callback function. + * @returns {Promise} + * + * @example + * const {PubSub} = require('@google-cloud/pubsub'); + * const pubsub = new PubSub(); + * const topic = pubsub.topic('my-topic'); + * + * const data = { + * foo: 'bar' + * }; + * + * const callback = (err, messageId) => { + * if (err) { + * // Error handling omitted. + * } + * }; + * + * topic.publishJSON(data, callback); + * + * //- + * // Optionally you can provide an object containing attributes for the + * // message. Note that all values in the object must be strings. + * //- + * const attributes = { + * key: 'value' + * }; + * + * topic.publishJSON(data, attributes, callback); + * + * //- + * // If the callback is omitted, we'll return a Promise. + * //- + * topic.publishJSON(data).then((messageId) => {}); + */ + publishJSON(json: object, attributes?: object): Promise; + publishJSON(json: object, callback: PublishCallback): void; + publishJSON(json: object, attributes: object, callback: PublishCallback): + void; + publishJSON(json: object, attributes?, callback?): Promise|void { + if (!is.object(json)) { + throw new Error('First parameter should be an object.'); + } + + const data = Buffer.from(JSON.stringify(json)); + return this.publish(data, attributes, callback); + } /** * Set the publisher options. * @@ -649,7 +709,7 @@ paginator.extend(Topic, ['getSubscriptions']); * that a callback is omitted. */ promisifyAll(Topic, { - exclude: ['publish', 'setPublishOptions', 'subscription'], + exclude: ['publish', 'publishJSON', 'setPublishOptions', 'subscription'], }); export {PublishOptions}; diff --git a/test/topic.ts b/test/topic.ts index da005b1d7..9cfba1949 100644 --- a/test/topic.ts +++ b/test/topic.ts @@ -29,7 +29,8 @@ const fakePromisify = Object.assign({}, pfy, { } promisified = true; assert.deepStrictEqual( - options.exclude, ['publish', 'setPublishOptions', 'subscription']); + options.exclude, + ['publish', 'publishJSON', 'setPublishOptions', 'subscription']); }, }); @@ -553,6 +554,37 @@ describe('Topic', () => { }); }); + describe('publishJSON', () => { + it('should throw an error for non-object types', () => { + const expectedError = /First parameter should be an object\./; + + assert.throws(() => topic.publishJSON('hi'), expectedError); + }); + + it('should transform JSON into a Buffer', () => { + const stub = sandbox.stub(topic, 'publish'); + const json = {foo: 'bar'}; + const expectedBuffer = Buffer.from(JSON.stringify(json)); + + topic.publishJSON(json); + + const [buffer] = stub.lastCall.args; + assert.deepStrictEqual(buffer, expectedBuffer); + }); + + it('should pass along the attributes and callback', () => { + const stub = sandbox.stub(topic, 'publish'); + const fakeAttributes = {}; + const fakeCallback = () => {}; + + topic.publishJSON({}, fakeAttributes, fakeCallback); + + const [, attributes, callback] = stub.lastCall.args; + assert.strictEqual(attributes, fakeAttributes); + assert.strictEqual(callback, fakeCallback); + }); + }); + describe('setPublishOptions', () => { it('should call through to Publisher#setOptions', () => { const fakeOptions = {};