diff --git a/README.md b/README.md index a75e0cc..5cb84dc 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Search for books matching the specified query. var books = require('google-books-search'); - books.search("Professional JavaScript for Web Developers", function(error, results) { + books.search('Professional JavaScript for Web Developers', function(error, results) { if ( ! error ) { console.log(results); } else { @@ -65,7 +65,17 @@ Returns an array of JSON objects. For example; For a description of each value; see the [Google Books API documentaion for volumes](https://developers.google.com/books/docs/v1/reference/volumes). -## Advanced Usage +### .lookup(volumeId, options, callback) + +Lookup books by Volume ID. + + books.lookup('9KJJYFIss_wC', function(error, result) { + ... + }); + +The options argument accepts an object with a `key` field (your API key). + +## Advanced Searches The search method optionally accepts an options object as the second argument. See below for an overview of the available options. diff --git a/lib/google-books-search.js b/lib/google-books-search.js index e3f3294..9e6be68 100644 --- a/lib/google-books-search.js +++ b/lib/google-books-search.js @@ -33,12 +33,14 @@ var fields = { // Base url for Google Books API -var API_BASE_URL = 'https://www.googleapis.com/books/v1/volumes?'; +var API_BASE_URL = 'https://www.googleapis.com/books/v1'; /** * Search Google Books * + * https://developers.google.com/books/docs/v1/reference/volumes/list + * * @param {String} query * @param {object} options * @param {Function} callback @@ -46,12 +48,12 @@ var API_BASE_URL = 'https://www.googleapis.com/books/v1/volumes?'; var search = function(query, options, callback) { // Make the options object optional - if (!callback || typeof callback != 'function') { + if (!_.isFunction(callback)) { callback = options; - options = undefined; + options = {}; } - var options = _.extend({}, defaultOptions, options || {}); + var options = _.extend({}, defaultOptions, options); // Validate options if (!query) { @@ -85,7 +87,7 @@ var search = function(query, options, callback) { query.key = options.key; } - sendRequest(query, function(err, response) { + sendRequest('/volumes', query, function(err, response) { if (err) { return callback(err); } @@ -104,13 +106,62 @@ var search = function(query, options, callback) { }; +/** + * Retrieves a Volume resource based on ID. + * + * https://developers.google.com/books/docs/v1/reference/volumes/get + * + * @param {String} volumeId + * @param {Function} callback + */ +var lookup = function(volumeId, options, callback) { + + var query = {}; + + // Make the options object optional + if (!_.isFunction(callback)) { + callback = options; + options = {}; + } + + if (!volumeId) { + return callback(new Error('Volume ID is required')); + } + + if (options.key) { + query.key = options.key; + } + + sendRequest('/volumes/' + volumeId, query, function(err, response) { + if (err) { + return callback(err); + } + + if (!response.id || response.id !== volumeId) { + return callback(null, null); + } + + callback(null, parseBook(response), response); + }); +}; + + /** * Send a Google Books API request * * @return {void} */ -var sendRequest = function(params, callback) { - var url = API_BASE_URL + querystring.stringify(params); +var sendRequest = function(path, params, callback) { + var url = API_BASE_URL; + + if (path) { + url += path; + } + + if (params) { + url += '?' + querystring.stringify(params); + } + https.get(url, function(response) { if (response.statusCode !== 200) { return callback(new Error('Google Books API error. Status Code: ' + response.statusCode)); @@ -125,7 +176,12 @@ var sendRequest = function(params, callback) { response.on('end', function() { try { var data = JSON.parse(body); - callback(null, data); + + if (data.error) { + callback(new Error(data.error.message)); + } else { + callback(null, data); + } } catch (e) { callback(new Error('Invalid response from Google Books API.')); } @@ -162,3 +218,4 @@ var parseBook = function(data) { module.exports.search = search; +module.exports.lookup = lookup; diff --git a/test/search-test.js b/test/search-test.js index f5bdecd..022604f 100644 --- a/test/search-test.js +++ b/test/search-test.js @@ -2,7 +2,7 @@ var mocha = require('mocha'); var should = require('should'); var books = require('../lib/google-books-search.js'); -describe('Searching', function() { +describe('Search', function() { it('should return a JSON object of books', function(done) { books.search('Guinness World Records', {}, function(error, results) { @@ -69,3 +69,26 @@ describe('Searching', function() { }); }); + + +describe('Lookup', function() { + + it('should return a JSON object of a volume', function(done) { + books.lookup('9KJJYFIss_wC', function(error, result) { + should.not.exist(error); + result.should.be.an.instanceof(Object); + result.id.should.equal('9KJJYFIss_wC'); + result.should.have.property('title'); + done(); + }); + }); + + it('should return an error if an invalid volume id is provided', function(done) { + books.lookup('this is not a real volume id', function(error, result) { + should.exist(error); + should.not.exist(result); + done(); + }); + }); + +});