Zak Dyer

Zak Dyer

1557931447

Building CLI Applications with NodeJS

A good example of commonly used applications include npm, eslint, typescript, and project generators, such as Angular CLI, Vue CLI or Create React App.

As a developer, chances are you spend most of your time in your terminal, typing in commands to help you get around some tasks.

Some of these commands come built into your Operating System, while some of them you install through some third party helper such as npm, or brew, or even downloading a binary and adding it to your $PATH.

Table of Contents

  1. Shebang
  2. What we’ll build
  3. Quote of the Day
  4. A Tiny To Do List
  5. Todo App: Help Command
  6. Todo App: New Command
  7. Todo App: Get Command
  8. TodoApp: Complete Command
  9. Libraries
  10. Rap

Shebang

This is the wikipedia definition:

Whenever you look at any scripting file, you’ll see characters such as the ones below in the beginning of the file.

#!/usr/bin/env sh

#!/usr/bin/env python -c

They serve as a way for your operating system program loader will help parse the correct interpreter for your executable file. This only works in Unix Systems though.

NodeJS too has it’s own supported shebang characters. Make sure you have NodeJS installed, and create a file called logger with the following content.

#!/usr/bin/env node

console.log("I am a logger")

The first line tells the program loader to parse this file with NodeJS. The rest of the file is just normal JavaScript.

You can try and run the file by typing this in your terminal. You’ll get a permission denied for execution.

./logger
zsh: permission denied: ./logger

You need to give the file execution permissions. You can do that with.

chmod +x logger
./logger
I am a logger

You’ll see the file log correctly.

This could also easily be achieved if we did node logger. But we want to have our own command, and not need to use node ... to run it.

What we’ll build

Now that you have a teaser, we’re going to look at two example applications that we can build to learn more about CLI apps.

  1. Quote Of The Day (qod) cli tool, that retrieves quotes of the day from https://quotes.rest/qod.
  2. A Tiny To Do List that uses JSON to save data.

Quote of the Day

Let’s create a directory and call it qod. And inside, instantiate a NodeJs app.

mkdir qod
cd qod
touch qod
npm init -y

Next, we know we need to make requests to the quotes server, so we could use existing libraries to do just this. We’ll use axios

npm install --save axios

We’ll also add a chalk, a library to help us print color in the terminal.

npm install --save chalk

We then write the logic needed to retrieve these quotes. Edit the qod file.

#!/usr/bin/env node

const axios = require('axios')
const chalk = require('chalk');

const url = "https://quotes.rest/qod"

// make a get request to the url
axios({
  method: 'get',
  url: url,
  headers: { 'Accept': 'application/json' }, // this api needs this header set for the request
}).then(res => {
  const quote = res.data.contents.quotes[0].quote
  const author = res.data.contents.quotes[0].author
  const log = chalk.green(`${quote} - ${author}`) // we use chalk to set the color green on successful response
  console.log(log)
}).catch(err => {
  const log = chalk.red(err) // we set the color red here for errors.
  console.log(log)
})

The above is normal NodeJS code, and all we are doing is calling an API endpoint. Change the file permissions with

chmod +x qod

Then run the application.

./qod

The best way to not feel hopeless is to get up and do something. Don’t wait for good things to happen to you. If you go out and make some good things happen, you will fill the world with hope, you will fill yourself with hope. - Barack Obama

It should appear green, as we stated with the color.

This is roughly the same as our first logger, but the point was to show that we can use existing libraries, and still run our apps the same way.

A Tiny To Do List

This will be a bit more complex, as it will involve data storage, and retrieval. Here’s what we’re trying to achieve.

  1. We need to have a command called todo
  2. The command will take in four arguments. new, get, complete, and help. So the available commands will be
./todo new // create a new todo
./todo get // get a list of all your todos
./todo complete // complete a todo item.
./todo help // print the help text

Seems straight forward.

Let’s create a directory called todo, and instantiate a nodejs app

mkdir todo
cd todo
touch todo
npm install -y

TIP - If you do a lot of creating directories and getting into the directories, you can save yourself some time by adding a function like this to your bash or zsh file.

# Create a new directory and enter it
function mkd() {
    mkdir -p "$@" && cd "$_";
}

Then, all you need to do is type in mkd directory_name, and you’ll be in there.

We’ll also install chalk again, so that we can log with colors.

npm install --save chalk

The first thing we’re going to do is make sure we have these commands available. To get the commands working, we’ll use NodeJs’ process/argv which returns a string array of command line arguments

In computing, a shebang is the character sequence consisting of the characters number sign and exclamation mark (#!) at the beginning of a script.
Add this to the todo file.

#!/usr/bin/env node

console.log(process.argv)

Give the file executable permissions, and then run it with a new command.

chmod +x ./todo
./todo new

You’re going to get this output.

[ '/Users/ganga/.nvm/versions/node/v8.11.2/bin/node',
  '/Users/ganga/Dev/scotch/todo/todo',
  'new' ]

Notice that the first two strings in the array are the interpreter and the file full path. In this case, these are my absolute path names. Then, the rest of the array contains whatever we passed, in this case it’s new.

To be safe, let’s restrict these, so that we can only accept the correct number of arguments, which is one, and they can only be new, get and complete.

Modify the todo file like shown below.

#!/usr/bin/env node

const chalk = require('chalk')
const args = process.argv

// usage represents the help guide
const usage = function() {
  const usageText = `
  todo helps you manage you todo tasks.

  usage:
    todo <command>

    commands can be:

    new:      used to create a new todo
    get:      used to retrieve your todos
    complete: used to mark a todo as complete
    help:     used to print the usage guide
  `

  console.log(usageText)
}

// used to log errors to the console in red color
function errorLog(error) {
  const eLog = chalk.red(error)
  console.log(eLog)
}

// we make sure the length of the arguments is exactly three
if (args.length > 3) {
  errorLog(`only one argument can be accepted`)
  usage()
}

We’ve first assigned the command line arguments to a variable, and then we check at the bottom that the length is not greater than three.

We’ve also added a usage string, that will print what the command line app expects. Run the app with wrong parameters like below.

./todo new app
only one argument can be accepted

todo helps you manage you todo tasks.

usage:
  todo <command>

  commands can be:

  new:      used to create a new todo
  get:      used to retrieve your todos
  complete: used to mark a todo as complete
  help:     used to print the usage guide

If you run it with one parameter, it will not print anything, which means the code passes.

Next, we need to make sure only the four commands are expected, and everything else will be printed as invalid.

Add a list of the commands at the top of the code.

//....
const commands = [&apos;new&apos;, &apos;get&apos;, &apos;complete&apos;, &apos;help&apos;]
//....

And then check with the passed in command after we’ve checked the length.

//...
if (commands.indexOf(args[2]) == -1) {
  errorLog(&apos;invalid command passed&apos;)
  usage()
}
//...

Now, if we run the app with an invalid command, we get this.

./todo ne
invalid command passed

  todo helps you manage you todo tasks.

  usage:
    todo <command>

    commands can be:

    new:      used to create a new todo
    get:      used to retrieve your todos
    complete: used to mark a todo as complete
    help:     used to print the usage guide

We’ll cover the rest of the logic in separate topics. For now, you can combine the argument checks into a single function as an exercises.

Todo App: Help Command

This is the most straight forward part of the app. All we need to do is call the usage function. Let’s add this to the todo file.

//...
switch(args[2]) {
  case &apos;help&apos;:
    usage()
    break
  case &apos;new&apos;:
    break
  case &apos;get&apos;:
    break
  case &apos;complete&apos;:
    break
  default:
    errorLog(&apos;invalid command passed&apos;)
    usage()
}
//...

We have a switch statement which will call functions based on what command has been called. If you look closely, you’ll notice the help case just calls the usage function.

While writing this I also noticed that the default case can serve as an error handler for invalid commands, so I deleted the check we did earlier, and the commands array. Thought I’d leave it there because refactoring is always fun.

Todo App: New Command

The new command will create a new todo item, and save it in a json file. We will use a file db, to help us with the storage files.

The library we will use is lowdb. We could easily write functions to read and write to a json file, if we wanted to.

Install lowdb

npm install --save lowdb

Let’s add [readline](<a href="https://nodejs.org/api/readline.html)" target="_blank">https://nodejs.org/api/readline.html)</a> and lowdb dependencies, to help us with storing data. The lowdb code is standard from their github page.

//...
const rl = require(&apos;readline&apos;);

const low = require(&apos;lowdb&apos;)
const FileSync = require(&apos;lowdb/adapters/FileSync&apos;)

const adapter = new FileSync(&apos;db.json&apos;)
const db = low(adapter)

// Set some defaults (required if your JSON file is empty)
db.defaults({ todos: []}).write()
//...

Next, we’ll add a function to prompt the user to input data.

//...
function prompt(question) {
  const r = rl.createInterface({
    input: process.stdin,
    output: process.stdout,
    terminal: false
  });
  return new Promise((resolve, error) => {
    r.question(question, answer => {
      r.close()
      resolve(answer)
    });
  })
}
//...

Here we are using the readline library to create an interface that will help us prompt a user to and then read the output.

Next, we need to add a function that will be called when a user types in the new command

//...
function newTodo() {
  const q = chalk.blue(&apos;Type in your todo\n&apos;)
  prompt(q).then(todo => {
    console.log(todo)
  })
}
//...

We’re using chalk to get the blue color for the prompt. And then we will log the result.

Lastly, call the function in the new case.

// ...
switch(args[2]) {
  //...
  case &apos;new&apos;:
    newTodo()
    break
    // ...
}
// ...

When you run the app now with the new command, you will be prompted to add in a todo. Type and press enter.

./todo new
Type in your todo
This my todo  aaaaaaw yeah
This my todo  aaaaaaw yeah

You should see something similar to this.

Notice also, that a db.json file has been created in your file system, and it has a todos property.

Next, let’s add in the logic for adding a todo. Modify the newTodo function.

//...
function newTodo() {
  const q = chalk.blue(&apos;Type in your todo\n&apos;)
  prompt(q).then(todo => {
    // add todo
    db.get(&apos;todos&apos;)
      .push({
      title: todo,
      complete: false
      })
      .write()
  })
}
//...

Run the code again.

./todo new
Type in your todo
Take a Scotch course

If you look at your db.json, you’ll see the todo added. Add two more, so that we can retrieve them in the next get command. Here’s mine.

{
  "todos": [
    {
      "title": "Take a Scotch course",
      "complete": false
    },
    {
      "title": "Travel the world",
      "complete": false
    },
    {
      "title": "Rewatch Avengers",
      "complete": false
    }
  ]
}

Todo App: Get Command

With knowledge from the new command, the get command should be simple to write.

Create a function that will retrieve the todos.

//...
function getTodos() {
  const todos = db.get(&apos;todos&apos;).value()
  let index = 1;
  todos.forEach(todo => {
    const todoText = `${index++}. ${todo.title}`
    console.log(todoText)
  })
}
//...

// switch statements
switch(args[2]) {
    //...
    case &apos;get&apos;:
        getTodos()
        break
    //...
}
//....

Running the app now, should give us this

./todo get
1. Take a Scotch course
2. Travel the world
3. Rewatch Avengers

You can make the color fancy/green by using chalk.green

TodoApp: Complete Command

The complete command is a little bit complicated.

We can do it in two ways.

  1. Whenever a user types in ./todo complete, we could list all the todos, and the ask them to type in the number/key for the todo to mark as complete.
  2. We can add in another parameter, so that a user can type in ./todo get, and then choose the task to mark as complete with a parameter, such as ./todo complete 1 .

Since we covered how option 1 is done in the new command, we’ll look at option 2.

A good problem introduced here is the ./todo complete 1, will surely surpass our validity check for the number of commands given. We therefore first need to handle this. Change the function that checks the length of the arguments with to this.

//...
// we make sure the length of the arguments is exactly three
if (args.length > 3 && args[2] != &apos;complete&apos;) {
  errorLog(&apos;only one argument can be accepted&apos;)
  usage()
  return
}
///...

Above approach is using the truth tables, where TRUE && FALSE will equal FALSE, and the code will be skipped when complete is passed.

We’ll then grab the value of the new argument and make the value of todo as completed like so

//...
function completeTodo() {
  // check that length
  if (args.length != 4) {
    errorLog("invalid number of arguments passed for complete command")
    return
  }

  let n = Number(args[3])
  // check if the value is a number
  if (isNaN(n)) {
    errorLog("please provide a valid number for complete command")
    return
  }

  // check if correct length of values has been passed
  let todosLength = db.get(&apos;todos&apos;).value().length
  if (n > todosLength) {
    errorLog("invalid number passed for complete command.")
    return
  }

  // update the todo item marked as complete
  db.set(`todos[${n-1}].complete`, true).write()
}
//...

I’ve made comments on each part of the code above. Please read through.

Make sure to update the switch statements.

//...
case &apos;complete&apos;:
    completeTodo()
    break
//...

When you run this with ./todo complete 2, you’ll notice your db.json has changed to this, marking the second task as complete.

{
  "todos": [
    {
      "title": "Take a Scotch course",
      "complete": false
    },
    {
      "title": "Travel the world",
      "complete": true
    },
    {
      "title": "Rewatch Avengers",
      "complete": false
    }
  ]
}

The last thing we need to do, is change ./todo get to only show tasks that are done. We’ll use emojis for this.

//...
function getTodos() {
  const todos = db.get(&apos;todos&apos;).value()
  let index = 1;
  todos.forEach(todo => {
    let todoText = `${index++}. ${todo.title}`
    if (todo.complete) {
      todoText += &apos; &#x2714; &#xFE0F;&apos; // add a check mark
    }
    console.log(chalk.strikethrough(todoText))
  })
  return
}
//...

When you now type in the ./todo get you’ll see this.

./todo get
1. Take a Scotch course
2. Travel the world &#x2714; &#xFE0F;
3. Rewatch Avengers

I know, it could be improved, but you get the idea.

That’s it for now.

Libraries

This is JavaScript, and of course some brilliant person out there has thought of all these and written helper libraries. The focus for this article was to look at how CLI applications are built with vanilla nodejs, but when working in the real world, it would be more productive to use libraries.

Here’s a list of helpful libraries to help you write awesome CLI applications, which you can publish to npm.

  1. vopral - fully featured interactive CLI framework
  2. meow - CLI helper library
  3. commanderjs - CLI library
  4. minimist - for arguments parsing
  5. yargs - arguments parsing

And not to mention libraries like chalk that helped us with colors.

Recap

I hope you got a thing or two about building CLI applications with NodeJS.

A common practice I did not mention is that, once your app is working fine, most libraries put the file into a bin folder, and this way, npm knows how to work with executables. This is not a requirement, but regardless of where you place the executable, you should update package.json bin property.

As an excercise, try to add a Delete command to the CLI.

#node-js

What is GEEK

Buddha Community

Building CLI Applications with NodeJS

Hire NodeJs Developer

Looking to build dynamic, extensively featured, and full-fledged web applications?

Hire NodeJs Developer to create a real-time, faster, and scalable application to accelerate your business. At HourlyDeveloper.io, we have a team of expert Node.JS developers, who have experience in working with Bootstrap, HTML5, & CSS, and also hold the knowledge of the most advanced frameworks and platforms.

Contact our experts: https://bit.ly/3hUdppS

#hire nodejs developer #nodejs developer #nodejs development company #nodejs development services #nodejs development #nodejs

How to Install NodeJS on Ubuntu 19.04

Overview
In this tutorial, you will learn how to install Node onto Ubuntu 19.04 Disco Dingo. We will cover installation from the default repositories and, for those wanting more recent releases, how to install from the NodeSource repositories.

Installing from Ubuntu
The Ubuntu 19.04 Disco Dingo repository includes NodeJS version 10.15. Like most packages found here, it certainly is not the most recent release; however, if stability is more important than features, it will be your preferred choice.

#nodejs #nodejs 10.x #nodejs 11.x #nodejs 12.x #nodejs 8.x

Top NodeJS Mobile App Development Company in USA

AppClues Infotech is one of the leading NodeJS app development company in USA that offering excellent NodeJS development services for web app development. We provide customized and high-quality NodeJS app development services to clients for different industries with advanced technology and functionalities.

Our dedicated app developers have years of experience in NodeJS development and thus successfully deliver cost-effective and highly customized solutions using the robust JavaScript engine of NodeJS.

Why Choose AppClues Infotech for NodeJS Application Development?
• Fast App Development
• Real-Time Application
• JSON (JavaScript Object Notation) in your Database
• Single Codebase
• Lower Cost
• Built-in NPM Support
• Inexpensive Testing and Hosting

For more info:
Website: https://www.appcluesinfotech.com/
Email: info@appcluesinfotech.com
Call: +1-978-309-9910

#top nodejs app development company in usa #nodejs web app development #nodejs development agency in usa #hire nodejs app developers in usa #custom nodejs app development company #best nodejs app development service company

Arvel  Miller

Arvel Miller

1603068240

Decoding Nodejs

The main goal of this blog is to explain the “Architecture of Nodejs” and to know how the Nodejs works behind the scenes,

Generally, most of the server-side languages, like PHP, ASP.NET, Ruby, and including Nodejs follows multi-threaded architecture. That means for each client-side request initiates a new thread or even a new process.

In Nodejs, all those requests from the clients are handled in a single-thread using shared resources concurrently as It follows the “Single-Threaded Event Loop Model”.

ARCHITECTURE OF NODEJS

What Is EVENT-LOOP?

Event-Loop programming is a flow control in an application-defined by events. The basic principle of Nodejs’s event-driven loop is implementing a central mechanism that hears for events and calls the callback function once an event is turning up.

Nodejs is an event-loop that implements a run-time environment model to achieve non-blocking asynchronous behavior runs on Google Chrome’s V8 engine.

#nodejs #nodejs-developer #nodejs-architecture #nodejs-tutorial #backend #javascript #beginners #event-loop

Created a Realtime Chat Application Using NodeJs and SocketIO

Created a Realtime Chat Application Using NodeJs and SocketIO

#nodejs #nodejs and socketio #application