-
Clone repo
-
Use the command line to
cdinto the root directory -
Run
npm install -
Execute
node index.js qto send a search query to Google Books API ornode index.js lsto view reading list -
Run
npx mochato run the specs. You can view the test cases in/test.
-
commander― module that helps us construct our CLI interface -
inquirer― creates interactive command-line user interface -
axios― light-weight module that allows us make requests to external services to fetch data -
[email protected]― light-weight JSON database for small projects -
chalk― colorizes command line output
The application's main dependency commander module is set up in the root directory file index.js, and provides the core functionality and interface for this command line application.
// index.js
const app = require('commander');
const { query, list } = require('./lib/commands');
app
.version('0.0.1')
.description('Search Google Books and create a reading list.')
app
.command('list')
.alias('ls')
.description('view the locally-stored reading list...')
.action(function () {
list();
});
app
.command('query')
.alias('q')
.description('search Google Books library for a title...')
.action(function() {
query();
});
app.parse(process.argv);Let’s go over what each piece of the code above does:
-
.versionallows us to define the current version of our command line application -
.commanddefines how the parameter should be passed to the program w/ any extra arguments -
.aliasdefines an alternative short form parameter that can be passed to the program instead of typing a longer one. -
descriptionis the description of the alias -
.actionwill call whatever function is passed to it. The action runs the functions and displays whatever is returned from the function. The action is also responsible for handling interactions with the user if the command line application is an interactive application.
The two commands enabled are list and query and can be executed also by the aliases ls or q, respectively. In other words, both commands can be run by calling
node index.js list
or
node index.js ls
The .action attributes of the commander CLI interface calls list or query, functions detailed in the commands.js file within the lib directory. The lib directory is where the "meat" of the application lives.
Because the list method performs the same logic as the end of the query method, we will not be covering the list method. The query method looks like this:
// lib/commands.js
query: async () => {
const search = await getSearchTerm();
const searchResults = await fetchBooks(search.term);
const selectedBooksToAdd = await addBooksToList(searchResults);
const rejectedTitles = [];
let readingList = db.get('books').value();
if (selectedBooksToAdd.selected.length) {
selectedBooksToAdd.selected.forEach(book => {
if (includedInReadingList(readingList, book)) {
rejectedTitles.push(book.title);
} else {
db.get('books')
.push(_.omit(book, 'aggregate'))
.write()
}
})
}
const readingListBooks = db.get('books').value();
console.log(chalk.cyan.bold('READING LIST'));
console.table(readingListBooks);
if (rejectedTitles.length) {
console.log(chalk.red(`These titles already exist in the reading list: ${rejectedTitles}`))
}
}-
First, we invoke and wait for
getSearchTerm, a method that uses theinquirermodule to ask for a search input from the user -
With this term, we pass it to
fetchBooks, which makes an axios query search to the Google Books API using this term, takes the first five search results, and trims the resulting books fortitle,authors, andpublisher -
selectedBooksToAddis anotherinquirerprocess which allows the user to select any number of the five search result books to add to the reading list, which is stored indb.jsonusing our dependencylowdb -
After the user selects which of the five books to add, a quick validation,
includedInReadingList, is run to ensure that no duplicate books are added to the reading list. -
Finally, we
console.tablethe information for each book within our local database, logic that is akin to that within thelistcommand.
