DEV Community

Cover image for How to create a CLI with Node.js
Matheus Tanaka
Matheus Tanaka

Posted on

How to create a CLI with Node.js

A command-line interface is a simple way to execute commands, mostly used by Operational Systems, like Linux, macOS, and Windows. But, it can be used to install packages and run scripts like git or npm.
Node.js is a great runtime to build CLI where you can run it on any machine that has Node installed.
By the way, this article is for anyone who wants to build your first CLI and automate little things.

Getting Started

First of all, you need to install Node.js runtime on your machine. If you don’t have Node.js installed, it can’t work. So, go to https://nodejs.org/en/ and download it.

We will use two packages to build the CLI:

  • node-fetch - is a fetch client that we can use to get the data from any API
  • yargs - will allow us to process any flags or arguments passed to the CLI

To install the packages, just type in your terminal:

npm install node-fetch yargs --save
Enter fullscreen mode Exit fullscreen mode

The API

There are so many public APIs, you can choose any API. I want to make a CLI that monitors cryptocurrency price, so I choose an API that Binance provide for us.

Coding

You should create a file called crypto.mjs, you can name it as you want, I put crypto because my CLI is about crypto, but feel free to rename it if you want. I recommend index.mjs or main.mjs, but whatever.

First, we will import our packages and define our interpreter, as you can see, we are using node.

#! /usr/bin/env node

import fetch from "node-fetch";

import yargs from "yargs";
Enter fullscreen mode Exit fullscreen mode

With everything imported, it’s time to code, let’s do that.

#! /usr/bin/env node

import fetch from "node-fetch";

import yargs from "yargs";

//The process.argv property returns an array containing the command-line arguments passed when the Node.js process was launched

const { argv } = yargs(process.argv);

//init fetch to binance api

const response = await fetch("<https://api2.binance.com/api/v3/ticker/24hr>");

const data = await response.json();

console.log(data);
Enter fullscreen mode Exit fullscreen mode

After fetching the data, we need to see if our response works correctly, I recommend putting a console.log(data) and checking the API response.

In Binance API there are so many cryptocurrencies listed, when you fetch them, will return so many cryptos.

Your response should be like that:

response-api

As you can see, it works. It’s impossible to list everything in a unique image, if you want to check all of these cryptos, you can install an API platform like Postman or Insomnia.

What’s the purpose of my CLI?

I defined three functions that CLI should do, then we will translate them into code.

  • Return The largest Crypto Coin Price in the last 24 Hours
  • Return Bitcoin Average Price in the last 24 Hours
  • Return Ethereum Average Price in the last 24 Hours
//The first function to return the largest crypto

//Defining the properties that we want to show with CLI

let largestPrice = "";

let symbol = "";

let priceChangePercent = "";

let highPrice = "";

let dollarUSLocale = Intl.NumberFormat("en-US"); // convert the value in dollar

//for each crypto, we should check the last price and return the largest

data.forEach((crypto) => {

if (crypto.lastPrice > largestPrice) {

largestPrice = crypto.lastPrice;

symbol = crypto.symbol;

priceChangePercent = crypto.priceChangePercent;

highPrice = crypto.highPrice;

}

});
Enter fullscreen mode Exit fullscreen mode

Maybe you are asking yourself why there are so many variables?

The answer is the API has so many properties, like lastPrice, symbol and others, so we need to define which properties we want to cover with CLI, I choose these with empty strings, but you can put more properties, just check the API response and create a variable to store the data.

How we will return the largest crypto?

data.forEach((crypto) => {

if (crypto.lastPrice > largestPrice) {

largestPrice = crypto.lastPrice;

symbol = crypto.symbol;

priceChangePercent = crypto.priceChangePercent;

highPrice = crypto.highPrice;

}

});
Enter fullscreen mode Exit fullscreen mode

Look at the API Response

{

symbol: 'BNBUSDT',

priceChange: '14.00000000',

priceChangePercent: '4.747',

weightedAvgPrice: '301.42344940',

prevClosePrice: '295.00000000',

lastPrice: '308.90000000',

lastQty: '4.30600000',

bidPrice: '308.90000000',

bidQty: '93.80300000',

askPrice: '309.00000000',

askQty: '214.39300000',

openPrice: '294.90000000',

highPrice: '310.70000000',

lowPrice: '292.10000000',

volume: '697249.05200000',

quoteVolume: '210167214.34190000',

openTime: 1652709545294,

closeTime: 1652795945294,

firstId: 551442887,

lastId: 551762252,

count: 319366

},

{

symbol: 'VENBNB',

priceChange: '0.00000000',

priceChangePercent: '0.000',

weightedAvgPrice: '0.00000000',

prevClosePrice: '0.14920000',

lastPrice: '0.00000000',

lastQty: '0.00000000',

bidPrice: '0.00000000',

bidQty: '0.00000000',

askPrice: '0.00000000',

askQty: '0.00000000',

openPrice: '0.00000000',

highPrice: '0.00000000',

lowPrice: '0.00000000',

volume: '0.00000000',

quoteVolume: '0.00000000',

openTime: 1652369888551,

closeTime: 1652456288551,

firstId: -1,

lastId: -1,

count: 0

},
Enter fullscreen mode Exit fullscreen mode

As you can see, we will loop through the API data, so here, in the response, I got two cryptos BNBUSDT and VENBNB. Our forEach will check if the property of BNBUSDT lastPrice is bigger than VENBNB lastPrice, if it’s truelargestPrice will store the lastPrice of BNB and check if the next crypto is largest than the last again.

With the logic done, it’s time to create our first command, go to package.json and type this below the script

"scripts": {

"test": "echo \\"Error: no test specified\\" && exit 1"

},

"bin": {

"crypto-status": "./crypto.mjs"

},
Enter fullscreen mode Exit fullscreen mode

The bin folder holds binary files, which are the actual executable code for your application or library.
With bin added, we will pass the argv and the flag, so come back to crypto.mjs file and type the rest of code, as you can see is argv.price is the command

// Commands CLI: crypto-status --price

if (argv.price) {

console.log(`

The largest Crypto Coin Price in the last 24 Hours\\n

Price: $${dollarUSLocale.format(largestPrice)}\\n

Symbol: ${symbol}\\n

Price Change Percent: %${priceChangePercent}\\n

High Price: $${dollarUSLocale.format(highPrice)}

`);

}
Enter fullscreen mode Exit fullscreen mode
  • Return The largest Crypto Coin Price in the last 24 Hours is done✅

Now we need to make the last two functions, they don’t have to verify if the price is bigger than the other, I just want to check the price of them, so I decided to put them inside of commands and filter the price in the last 24 hours.

I will pass the argument and the flag, then we can filter these properties that we want to execute with CLI.

// Commands CLI: crypto-status --ethereum

if (argv.ethereum) {

data.filter((crypto) => {

if(crypto.symbol == "ETHUSDT") {

console.log(`

Ethereum Avarage Price in the last 24 Hours\\n

Symbol: ${crypto.symbol}\\n

Price: $${dollarUSLocale.format(crypto.lastPrice)}\\n

Price Change Percent: %${crypto.priceChangePercent}\\n

High Price: $${dollarUSLocale.format(crypto.highPrice)}`)

}

})

}

// Commands CLI: crypto-status --bitcoin

if (argv.bitcoin) {

data.filter((crypto) => {

if(crypto.symbol == "BTCUSDT") {

console.log(`

Bitcoin Avarage Price in the last 24 Hours\\n

Symbol: ${crypto.symbol}\\n

Price: $${dollarUSLocale.format(crypto.lastPrice)}\\n

Price Change Percent: %${crypto.priceChangePercent}\\n

High Price: $${dollarUSLocale.format(crypto.highPrice)}`)

}

})

}
Enter fullscreen mode Exit fullscreen mode
  • Return Bitcoin Average Price in the last 24 Hours is done✅
  • Return Ethereum Average Price in the last 24 Hours is done✅

Final Code

#! /usr/bin/env node

import fetch from "node-fetch";

import yargs from "yargs";

const { argv } = yargs(process.argv);

const response = await fetch("<https://api2.binance.com/api/v3/ticker/24hr>");

const data = await response.json();

let largestPrice = "";

let symbol = "";

let priceChangePercent = "";

let highPrice = "";

let dollarUSLocale = Intl.NumberFormat("en-US");

data.forEach((crypto) => {

if (crypto.lastPrice > largestPrice) {

largestPrice = crypto.lastPrice;

symbol = crypto.symbol;

priceChangePercent = crypto.priceChangePercent;

highPrice = crypto.highPrice;

}

});

// Commands CLI: crypto --price

if (argv.price) {

console.log(`

The largest Crypto Coin Price in the last 24 Hours\\n

Price: $${dollarUSLocale.format(largestPrice)}\\n

Symbol: ${symbol}\\n

Price Change Percent: %${priceChangePercent}\\n

High Price: $${dollarUSLocale.format(highPrice)}

`);

}

// Commands CLI: crypto-status --ethereum

if (argv.ethereum) {

data.filter((crypto) => {

if(crypto.symbol == "ETHUSDT") {

console.log(`

Ethereum Avarage Price in the last 24 Hours\\n

Symbol: ${crypto.symbol}\\n

Price: $${dollarUSLocale.format(crypto.lastPrice)}\\n

Price Change Percent: %${crypto.priceChangePercent}\\n

High Price: $${dollarUSLocale.format(crypto.highPrice)}`)

}

})

}

// Commands CLI: crypto-status --bitcoin

if (argv.bitcoin) {

data.filter((crypto) => {

if(crypto.symbol == "BTCUSDT") {

console.log(`

Bitcoin Avarage Price in the last 24 Hours\\n

Symbol: ${crypto.symbol}\\n

Price: $${dollarUSLocale.format(crypto.lastPrice)}\\n

Price Change Percent: %${crypto.priceChangePercent}\\n

High Price: $${dollarUSLocale.format(crypto.highPrice)}`)

}

})

}
Enter fullscreen mode Exit fullscreen mode

Your code should look like the code above.

Now you can test these commands in your terminal to check if everything is working.

$ node crypto.mjs crypto-status --price
Enter fullscreen mode Exit fullscreen mode
$ node crypto.mjs crypto-status --bitcoin
Enter fullscreen mode Exit fullscreen mode
$ node crypto.mjs crypto-status --ethereum
Enter fullscreen mode Exit fullscreen mode

cli-result

How to install our package locally?

Lastly, we must install our package locally so we can test out the CLI. We could just execute the file with the node runtime, but we want to see the CLI work.

bash npm install -g

We can simply install with no args which tells npm to install the current director. The -g flag means we want to globally install this package vs in a local node_modules.

You should now be able to run and see your log print.

bash crypto-status

Hopefully, the tutorial above helped you to learn more about Node.js and CLI. If you have any doubt, feel free to leave comments about them.

If you learned something from this article, please hit the like button.

Top comments (0)