Skip to content
This repository has been archived by the owner on Jul 27, 2020. It is now read-only.

Commit

Permalink
Merge pull request #51 from Financial-Times/v3-complex-search
Browse files Browse the repository at this point in the history
Added low-level complex search method.  Also added test-debug target
  • Loading branch information
aintgoin2goa committed Oct 15, 2014
2 parents ffa6e91 + 2495593 commit 7117804
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 84 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
test:
@./node_modules/.bin/mocha test test/models

test-debug:
@./node_modules/.bin/mocha --debug-brk test test/models

example:
@export DEBUG=*; export apikey=`cat ~/.ftapi`; node examples/article
104 changes: 104 additions & 0 deletions lib/v1/complexSearch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* This is the low-level search function used my other search methods
* It is not very user-friendly and isn't currently in the public API
* Call it with an object like this:
*
var searchBodyTemplate = {
"queryString":"",
"queryContext":{
"curations":["ARTICLES"]
},
"resultContext":{
"aspects" : ["editorial","images","lifecycle","location","master","metadata","nature","summary","title"],
"maxResults": 5,
"offset":0,
"contextual": true,
"highlight": false,
"facets":{
"names":["organisations"],
"maxElements":-1,
"minThreshold":100
}
};
*/
'use strict';

var request = require('request');
var model = require('../../models');
var debug = require('debug')('ft-api-client:api');
var v1 = require('./');

var endpoint = 'http://api.ft.com/content/search/v1';

function curry(){
var func = arguments[0],
args = [].slice.call(arguments, 1),
context = this;

return function(){
var allArgs = args.concat([].slice.call(arguments, 0));
return func.apply(context, allArgs);
}
}

function onResponse (resolve, reject, err, response, body){
if (err) {
debug('rejected - %s', endpoint);
return reject(err);
}

debug('resolved %s %s', endpoint, response.statusCode);

if (response.statusCode >= 400) {
resolve(undefined); // so as not to fail the Promise.all when we get a 4xx or 5xx we mask it
}

try {
body = JSON.parse(body);
} catch (error) {
debug('rejected - could not parse body response for %s', endpoint);
return reject('error parsing JSON');
}

// FIXME - handle 404 and/or no results
if (!body.results) {
reject('no results found');
return;
}

// was a valid request, but had no results so don't reject just resolve with empty array
if(body.results.length && !body.results[0].results){
resolve([]);
return;
}

resolve(body.results[0].results.map( function (article) {
return new model.Article({ item: article }); // make it look like an normal Content API body
})
);
}

function complexSearch(requestBody){
var callback;
var self = this;

return new Promise(function(resolve, reject){
callback = curry(onResponse, resolve, reject);

debug('requested %s', endpoint);

request({
url: endpoint,
qs: {
apiKey: self.apiKey
},
headers: self.headers,
method: 'post',
body: JSON.stringify(requestBody),
timeout: 2000
}, callback);
});
}

module.exports = complexSearch;
3 changes: 2 additions & 1 deletion lib/v1/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
exports.items = require('./items');
exports.page = require('./page');
exports.search = require('./search');
exports.request = require('./requestHandler');
exports.request = require('./requestHandler');
exports.complexSearch = require('./complexSearch');
91 changes: 17 additions & 74 deletions lib/v1/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,81 +18,24 @@ module.exports = function (term, quantity) {
var self = this;

var searchBodyTemplate = {
"queryString":"",
"queryContext":{
"curations":["ARTICLES"]
},
"resultContext":{
"aspects" : ["editorial","images","lifecycle","location","master","metadata","nature","summary","title"],
"maxResults": 5,
"offset":0,
"contextual": true,
"highlight": false,
"facets":{
"names":["organisations"],
"maxElements":-1,
"minThreshold":100
}
"queryString":term,
"queryContext":{
"curations":["ARTICLES"]
},
"resultContext":{
"aspects" : ["editorial","images","lifecycle","location","master","metadata","nature","summary","title"],
"maxResults": quantity || 5,
"offset":0,
"contextual": true,
"highlight": false,
"facets":{
"names":["organisations"],
"maxElements":-1,
"minThreshold":100
}
};

var promiseOfSearch = function(term, quantity) {
return function(resolve, reject) {

searchBodyTemplate.queryString += term;
searchBodyTemplate.resultContext.maxResults = quantity || 5;

var endpoint = 'http://api.ft.com/content/search/v1';

debug('requested %s', endpoint);

request({
url: endpoint,
qs: {
apiKey: self.apiKey
},
headers: self.headers,
method: 'post',
body: JSON.stringify(searchBodyTemplate),
timeout: 2000
}, function (err, response, body) {

if (err) {
debug('rejected - %s', endpoint);
return reject(err);
}

debug('resolved %s %s', endpoint, response.statusCode);

if (response.statusCode >= 400) {
resolve(undefined); // so as not to fail the Promise.all when we get a 4xx or 5xx we mask it
}

try {
body = JSON.parse(body);
} catch (error) {
debug('rejected - could not parse body response for %s', endpoint);
return reject('error parsing JSON');
}

// FIXME - handle 404 and/or no results
if (!body.results) {
reject('no results found');
return;
}
}
};

// was a valid request, but had no results so don't reject just resolve with empty array
if(body.results.length && !body.results[0].results){
resolve([]);
return;
}
return v1.complexSearch.call(self, searchBodyTemplate);

resolve(body.results[0].results.map( function (article) {
return new model.Article({ item: article }); // make it look like an normal Content API body
})
);
});
};
};
return new Promise(promiseOfSearch(term, quantity));
};
17 changes: 8 additions & 9 deletions test/apiSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,12 @@ describe('API', function(){
});
});

it.only('Should not die when no search results are returned', function(done){
nock(host).filteringRequestBody(/.*/, '*').post(util.format(searchPath, '123'), '*').reply(200, fixtures.searchNoResults);
ft.search('brand:Apple')
.then(function(articles){
expect(articles.length).to.equal(0);
done();
}, done)
});

it('Should not die when search returns zero results', function(done){
nock(host).filteringRequestBody(/.*/, '*').post(util.format(searchPath, '123'), '*').reply(200, fixtures.searchNoResults);
ft.search('brand:Apple')
.then(function(articles){
expect(articles.length).to.equal(0);
done();
}, done)
});
});

0 comments on commit 7117804

Please sign in to comment.