diff --git a/README.md b/README.md index de9806e..3a90be5 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,8 @@ # Node Bing API -Node.js lib for the Azure Bing Web Search API +Node.js lib for the Microsoft Cognitive Services Bing Web Search API ## Changelog v3 -Thanks to the contribution of [@franciscofsales](https://github.com/franciscofsales), version 3 supports the -new API (Cognitive Services). This version is not compatible with the -Azure version, so if you are still using an Azure access key, please -stay with v2. +Thanks to the contribution of [@franciscofsales](https://github.com/franciscofsales), version 3 supports the new API (Cognitive Services). ## Changelog v2 In order to follow JavaScript best practices and allow the library to diff --git a/lib/bing.js b/lib/bing.js index 0f697dc..1fae5f8 100644 --- a/lib/bing.js +++ b/lib/bing.js @@ -30,19 +30,14 @@ var Bing = function (options) { userAgent: 'Bing Search Client for Node.js', //Request Timeout - reqTimeout: 5000, - - // Number of results (limited to 50 by API) - top: 50, - - // Number of skipped results (pagination) - skip: 0 - + reqTimeout: 5000 }; - //merge options passed in with defaults + // Merge options passed in with defaults this.options = _.extend(defaults, options); + + // Performs the search request for the given vertical this.searchVertical = function (query, vertical, options, callback) { if (typeof options === 'function') { @@ -59,66 +54,49 @@ var Bing = function (options) { _.extend(opts, options); } - opts.videoSortBy = opts.videoSortBy || opts.videosortby || null; - opts.videoFilters = opts.videoFilters || opts.videofilters || null; + // Map options and supported variation for old versions with the new names + var opMap = { + top: 'count', + skip: 'offset', + videosortby: 'videoSortBy', + videofilters: 'videoFilters', + adult: 'safeSearch', + safesearch: 'safeSearch', + market: 'mkt' + } + Object.keys(opts).forEach(function (opt) { + var newOp = opMap[opt] + if (newOp) { + opts[newOp] = opts[newOp] || opts[opt] + delete opts[opt] + } + }) - var reqUri = opts.rootUri - + vertical - + (vertical == 'spellcheck' ? "?text=" : "?q=") + query - + (opts.top ? "&count=" + opts.top : "") - + (opts.offset ? "&offset=" + opts.skip : "") - + (opts.preContextText ? "&preContextText=" + opts.preContextText : "") - + (opts.mode ? "&mode=" + opts.mode : "") - + (opts.postContextText ? "&postContextText=" + opts.postContextText : "") - // + "&Options='" + (opts.options || []).join('%2B') + "'" - + (opts.sources - ? "&Sources='" + encodeURIComponent(opts.sources) + "'" - : '') - + (opts.market ? "&mkt='" + opts.market + "'" : '') - + (opts.adult ? "&safesearch=" + opts.adult : ''); + var reqUri = opts.rootUri + vertical + "?q=" + query + // Filter the no-query options (accKey, rootUri, userAgent) + var queryOpts = {} - var ignore = [ - 'spellcheck', - 'top', - 'offset', - 'preContextText', - 'mode', - 'postContextText', - 'sources', - 'market', - 'adult', - 'accKey', - 'reqTimeout', - 'rootUri', - 'skip', - 'top', - 'userAgent', - 'videoFilters', - 'videoSortBy' - ]; + Object.keys(opts).forEach(function (opt) { + if (!~Object.keys(defaults).indexOf(opt)) { + queryOpts[opt] = opts[opt] + } + }) - // clone object - var newOpts = JSON.parse(JSON.stringify(opts)); + var qStr = qs.stringify(queryOpts); - ignore.forEach(function(key) { - delete newOpts[key]; - }); - - var qStr = require('querystring').stringify(newOpts); - - reqUri += '&' + qStr; + reqUri += qStr ? '&' + qStr : ''; request({ uri: reqUri, method: opts.method || "GET", headers: { - "User-Agent": opts.userAgent, - "Ocp-Apim-Subscription-Key": opts.accKey + "User-Agent": opts.userAgent, + "Ocp-Apim-Subscription-Key": opts.accKey }, timeout: opts.reqTimeout, pool: { - maxSockets: opts.maxSockets ? opts.maxSockets : Infinity + maxSockets: opts.maxSockets ? opts.maxSockets : Infinity } }, function (err, res, body) { @@ -127,8 +105,8 @@ var Bing = function (options) { err = new Error(body); } else { - // Parse body, if body - body = typeof body === 'string' ? JSON.parse(body) : body; + // Parse body, if body + body = typeof body === 'string' ? JSON.parse(body) : body; } callback(err, res, body); @@ -153,7 +131,7 @@ var Bing = function (options) { * * @param {Object} options Options to command, allows overriding * of rootUri, accKey (Bing API key), - * userAgent, reqTimeout, top, skip + * userAgent, reqTimeout, count, offset * * @param {requestCallback} callback Callback called with (potentially * json-parsed) response. @@ -176,7 +154,7 @@ Bing.prototype.search = Bing.prototype.web; * * @param {Object} options Options to command, allows overriding * of rootUri, accKey (Bing API key), - * userAgent, reqTimeout, top, skip, + * userAgent, reqTimeout, count, offset, * * @param {requestCallback} callback Callback called with (potentially * json-parsed) response. @@ -193,7 +171,7 @@ Bing.prototype.composite = function (query, options, callback) { * * @param {Object} options Options to command, allows overriding * of rootUri, accKey (Bing API key), - * userAgent, reqTimeout, top, skip, + * userAgent, reqTimeout, count, offset, * * @param {requestCallback} callback Callback called with (potentially * json-parsed) response. @@ -210,7 +188,7 @@ Bing.prototype.news = function (query, options, callback) { * * @param {Object} options Options to command, allows overriding * of rootUri, accKey (Bing API key), - * userAgent, reqTimeout, top, skip, + * userAgent, reqTimeout, count, offset, * * @param {requestCallback} callback Callback called with (potentially * json-parsed) response. @@ -246,7 +224,7 @@ Bing.prototype.video = function (query, options, callback) { * * @param {Object} options Options to command, allows overriding of * rootUri, accKey (Bing API key), - * userAgent, reqTimeout, top, skip, + * userAgent, reqTimeout, count, offset, * imageFilters * * @param {requestCallback} callback Callback called with (potentially @@ -282,7 +260,7 @@ Bing.prototype.images = function (query, options, callback) { * * @param {Object} options Options to command, allows overriding * of rootUri, accKey (Bing API key), - * userAgent, reqTimeout, top, skip, + * userAgent, reqTimeout, count, offset, * * @param {requestCallback} callback Callback called with (potentially * json-parsed) response. @@ -300,7 +278,7 @@ Bing.prototype.relatedSearch = function (query, options, callback) { * * @param {Object} options Options to command, allows overriding * of rootUri, accKey (Bing API key), - * userAgent, reqTimeout, top, skip, + * userAgent, reqTimeout, count, offset, * * @param {requestCallback} callback Callback called with (potentially * json-parsed) response. @@ -317,7 +295,7 @@ Bing.prototype.spelling = function (query, options, callback) { * * @param {String} s String to be capitalised * - * @funtion + * @function */ function capitalise(s) { return s.charAt(0).toUpperCase() + s.slice(1); @@ -325,3 +303,4 @@ function capitalise(s) { module.exports = Bing; + diff --git a/test/integration.js b/test/integration.js index e887c37..d43a01b 100644 --- a/test/integration.js +++ b/test/integration.js @@ -23,19 +23,19 @@ describe("Bing Web", function () { it('works without options', function (done) { - Bing.web('monkey vs frog', function (err, res, body) { + Bing.web('pizza', function (err, res, body) { should.not.exist(err); should.exist(res); should.exist(body); - body.webPages.value.should.have.length(50); + body.webPages.value.length.should.be.above(0); //TODO check it contains the right fields done(); }); }); - it('finds only 5 results', function (done) { + it('finds only 5 results with old "top" option', function (done) { Bing.web('monkey vs frog', { top: 5, @@ -57,7 +57,7 @@ describe("Bing Web", function () { it('finds russian results', function(done){ Bing.web('"Sony Xperia Z3" смартфон', { - top: 5, + count: 5, skip: 0, market: 'ru-RU' }, @@ -205,25 +205,3 @@ describe("Bing Related Search", function () { }); }); - -describe("Bing Spelling Suggestion", function () { - - this.timeout(1000 * 10); - - it('finds proper spelling', function (done) { - - Bing.spelling('awsome spell', - function (err, res, body) { - - should.not.exist(err); - should.exist(res); - should.exist(body); - - // Find at leas one suggestion - body.flaggedTokens.suggestions.length.should.be.aboveOrEqual(1); - body.flaggedTokens.suggestions[0].suggestion.should.equal("awesome spell"); - - done(); - }); - }); -});