A Command Line Tool for Querying Bitcoin Price Information

Written by NickWal

This tutorial demonstrates how to create a nodejs command line tool, and a very basic reusable JavaScript service which can be re-used in many different environments. It also touches on writing tests for the service which is good practice. The example of a bitcoin price querying service is used because the API is freely available, and doesn’t require any authentication or API keys and so one which can complicate what is designed to be a simple tutorial.

This tutorial assumes you’ve successfully installed nodejs and have a code editor. The example here will always try to be operating system agnostic. It should work on any platform that nodejs runs on.

Project Setup

In this tutorial I’ll use a method of initializing a project which lends itself a little bit more to scripting than the regular npm init. Instead if you use npm init -y you can create a project using sensible default, furthermore you can personalize some of the defaults like this:

    npm config set init.author.name <name>
    npm config set init.author.email <email>

So create a new directory mkdir crprice or md crprice or whatever your operating system supports and cd to it. Then use the following:

   npm install -g npm-package-bin xo ava gulp-cli
   npm init -y
   xo --init --esnext
   ava --init
   npm install --save bluebird request request-promise woofwoof 
   npm install --save-dev ava xo 

   npm-bin add crprice ./price-tool.js -n

A quick note on npm-package-bin. This is a command line tool which you can use to edit the ‘bin’ section of package.json. The bin section contains the definitions of the tools or commands that would be installed if you use npm link or npm install -g

Price Service

Next we need to create the price service. This is the core piece of JavaScript which we will attempt to re-use in as many environments as possible. While this piece of code is actually very simple, it does call an external API, which is often a key feature of business logic in applications today. The API called is coinmarketcaps ticker API. In this tutorial we’ll just be making use of the functionality which returns the price of bitcoin in USD, however the API can return the price of very many cryptocurrencies such as ethereum, steem and others.

The price service uses the module request-promise which is a promisified version of the popular request library. The request library supports most technologies which you need to call an API including various types of authentication such as OAUTH and OAUTH2. Programming with promises is an extremely useful design pattern programming in an async environment like Nodejs, and prevents complications such as multiple nested callbacks which you need to use in more conventional programming patterns. The price-service module itself exports a factory function, that is a function which creates an object that calls the service. This improves the usability of the code - and makes integration with AngularJS especially easy.

Below the full source code of the service. Just copy and paste this and save with a name price-service.js

   /* jshint node:true */
   /* jshint esversion:6 */
   'use strict';
   const rp = require('request-promise');

   // https://coinmarketcap.com/api/

   module.exports = function () {
       this.getPrice = function (id) {
           const uri = 'https://api.coinmarketcap.com/v1/ticker/' + id + '/';
           const options = {
               url: uri,
               json: true
           };
           return rp.get(options).then(a => {
               return a;
           });
       };
   };

Command line

The price-tool.js script itself is a very simple wrapper around the the Price Service, which passes on the parameters from the user to the service, and then displays the result on the console. Of note in the price-tool.js script is the use of the module woofwoof which does away with a lot of the hard work of parsing arguments form the command line, saving settings and providing help.

Below the full source code of the tool. Just copy and paste this and save with a name price-tool.js

   #!/usr/bin/env node

   /* jshint node:true */
   /* jshint esversion:6 */
   'use strict';

   const woofwoof = require('woofwoof');
   const service = new (require('./price-service'))();

   const cli = woofwoof(`
       Usage
       $ crprice <input>

       Options
       --currency, -c  Check this currency

   `, {
       alias: {
           c: 'currency',
           a: 'all'
       },
       default: {
           all: false,
           currency: 'bitcoin'
       }
   });

   function p(a) {
       return JSON.stringify(a, null, 4);
   }

   if (cli.flags.all) {
       service.getPrice('').then(p).then(console.log);
   } else {
       service.getPrice(cli.flags.currency).then(p).then(console.log);
   }

Unit Testing

Finally a quick mention of testing. As an application becomes more complex, its important to be assured that all parts of the application are behaving as expected. Unit testing helps ensure this is the case. Below is a simple test which ensures that if we ask for the bitcoin price, its the bitcoin price we get (and not some other cryptocurrency!)

   /* jshint node:true */
   /* jshint esversion:6 */
   /* eslint ava/prefer-async-await:0 */

   import test from 'ava';
   import S from './price-service';

   test('return object', t => {
       var service = new S();
       return service.getPrice('bitcoin').then(result => {
           t.is(result[0].id, 'bitcoin');
       });
   });

To run the tests, use the command npm test

Using the tool

The file package.json should now look similar to this:

   {
     "name": "crprice",
     "version": "0.0.1",
     "description": "CLI tool to show price of cryptocurrencies",
     "main": "price-tool.js",
     "scripts": {
       "test": "xo && ava"
     },
     "bin": "./price-tool.js",
     "author": {
       "name": "Nicholas Waltham",
       "email": "[email protected]",
       "url": "www.infohit.net"
     },
     "license": "MIT",
     "dependencies": {
       "bluebird": "^3.4.6",
       "request": "^2.75.0",
       "request-promise": "^4.1.1",
       "woofwoof": "^3.6.6"
     },
     "devDependencies": {
       "ava": "^0.16.0",
       "xo": "^0.17.0"
     }
   }

Hopefully the only difference should be the name and contact details of the author. You can install and try out this tool like this

    npm link
    crprice

In Part 2. You’ll learn how to use the same price service as part of a web application. The web application will run entirely in the browser, and won’t require any server site components.