You may have heard of Command-line applications (CLI) as the core tools for tasks of automating. For instance, running tests, building reports, deploying production applications, DevOps, migrating data, etc. So, if you have to repeat the same things over and over again then you have the option to automate those steps with a script. This will save a lot of your time. In this blog, we will discuss the topic of Node.js request. Because Node.js is a great solution for writing CLI apps. Node.js contains inbuilt libraries that you can use for reading and writing files, basic network communication, and launching other applications. Additionally, there are various packages available on npm
for almost most of the imaginable tasks.

Also Read: Node js on hosting: Best Hosting Platforms for 2021
Building first Node.js request Command Line Application
To complete this tutorial you will require the following things:
- Firstly, most recent version of Node.js downloaded and installed
- Secondly, a nice text editor like Visual Studio Code.
- Lastly, you require a free Okta developer account
Now you have to open your computer’s command prompt (Windows) or terminal (macOS/Linux). You also have to change the current directory to that folder where you are saving your projects or documents. After doing so, enter the command mentioned below for creating a new project folder and initializing the project.
mkdir hello-cli cd hello-cli npm init
You have to open the hello-cli folder in your text editor now. After that, create a folder called bin and add a new file to that folder that goes by the name of index.js. Then open the index.js file in your favorite text editor and write the command mentioned below.
#!/usr/bin/env node console.log( "Hello!" );
In the above command, you can see that the first line is beginning with #!
what is usually known as a “shebang.” You can use this normally on Linux or UNIX operating systems only. It is used for informing the system of the type of script included in the rest of the text file.
Now you have to open the package.json
file in the root of the project in the text editor. Also, change the main
value to bin/index.js
. Along with the text mentioned below, you also have to add a new key for bin
.
"bin": { "hello": "./bin/index.js" }
Your entire package.json
file will look similar to the file mentioned below:
{ "name": "hello-cli", "version": "1.0.0", "description": "", "main": "bin/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "David Neal (https://reverentgeek.com)", "license": "MIT", "bin": { "hello": "./bin/index.js" } }
You can run the script like any other Node.js application at this point. So, enter the following command line.
node .
But the basic goal of writing such a script is to be able to run it from anywhere. You can do so with the npm install
command.
npm install -g .
Now this will install your script “globally.” All the commands available in the bin
section of the package.json
file will be accessed as command-line applications. So, now you can run your script by typing hello
at the command line!
hello
You have to run the below-mentioned command for uninstalling your script.
npm uninstall -g hello-cli
Making text stand out with Colour and Borders
Your job will be done by writing plain text directly to the console. However, it is nicer or sometimes necessary to have your content stand out. For instance, you can make error messages appear using the color Red. For modifying the color of text and background, we recommend you use chalk
. You can add borders around your text for making it more visible by using a module called boxen
. So, you can add both of them to your projects.
npm install chalk@2.4 boxen@4.0
Now you have to replace the contents of bin/index.js
with the code mentioned below.
#!/usr/bin/env node const chalk = require("chalk"); const boxen = require("boxen"); const greeting = chalk.white.bold("Hello!"); const boxenOptions = { padding: 1, margin: 1, borderStyle: "round", borderColor: "green", backgroundColor: "#555555" }; const msgBox = boxen( greeting, boxenOptions ); console.log(msgBox);
Thereafter, you have to install the updated script and run it.
npm install -g . hello
Lastly, the message in your console will look similar to the image below.

Add Support for Command Line Arguments
Most of the CLI applications accept one or more command-line arguments. For instance, commands, optional/required parameters, flags/switches, or other configuration values. Even though you have the option to parse command line parameters by inspecting the Node.js process.argv
value. It will be better to use the modules available as it will save you a lot of effort and time. The yargs
module is an example of such a module for Node.js whose design is to support the most common CLI scenarios.
Firstly, you have to install the yargs
module as a dependency for your application.
npm install yargs@13.2
Secondly, you have to update the bin/index.js
file with the help of the code mentioned below.
#!/usr/bin/env node const yargs = require("yargs"); const options = yargs .usage("Usage: -n <name>") .option("n", { alias: "name", describe: "Your name", type: "string", demandOption: true }) .argv; const greeting = `Hello, ${options.name}!`; console.log(greeting);
The previous code will help you in importing the yargs
module and configuring it to require one argument for name
. Then, install the updated script globally.
npm install -g .
It is necessary to have the name
parameter (demandOption: true
). So, when you run the hello
script the same as before, you will see something similar to the following.
> hello Usage: -n <name> Options: --help Show help [boolean] --version Show version number [boolean] -n, --name Your name [string] [required] Missing required argument: n
The yargs
module creates an amazing response for displaying help automatically. The CLI is not only ready for accepting -n
and --name
arguments but also --help
and --version
. Now you should try to run your CLI application with any of the following arguments.
> hello -n me Hello, me! > hello --version 0.1.0
Call your Node.js request API from the Command-line
There is a common scenario in automating tasks which are calling an API endpoint to get data or to send data to an API endpoint. In this part of our blog, we are going to take a random joke from a joke API and display it in the console. To retrieve and send data to an API in Node.js request, we recommend you use one of the popular libraries called axios
. You have to start by adding this library as a dependency.
npm install axios@0.21.1
Now you have to replace the contents of bin/index.js
with the below-mentioned code.
#!/usr/bin/env node const yargs = require("yargs"); const axios = require("axios"); const options = yargs .usage("Usage: -n <name>") .option("n", { alias: "name", describe: "Your name", type: "string", demandOption: true }) .argv; const greeting = `Hello, ${options.name}!`; console.log(greeting); console.log("Here's a random joke for you:"); const url = "https://icanhazdadjoke.com/"; axios.get(url, { headers: { Accept: "application/json" } }) .then(res => { console.log(res.data.joke); });
Along with responding with a greeting, the CLI application can also now retract a random joke using axios
and display it immediately after the greeting.
Adding a Search Argument to Node.js request Command-line Application
We can take the CLI Application one step ahead by supporting a search argument. You have to replace the contents of bin/index.js
with the below-mentioned code.
#!/usr/bin/env node const yargs = require("yargs"); const axios = require("axios"); const options = yargs .usage("Usage: -n <name>") .option("n", { alias: "name", describe: "Your name", type: "string", demandOption: true }) .option("s", { alias: "search", describe: "Search term", type: "string" }) .argv; const greeting = `Hello, ${options.name}!`; console.log(greeting); if (options.search) { console.log(`Searching for jokes about ${options.search}...`) } else { console.log("Here's a random joke for you:"); } // The url depends on searching or not const url = options.search ? `https://icanhazdadjoke.com/search?term=${escape(options.search)}` : "https://icanhazdadjoke.com/"; axios.get(url, { headers: { Accept: "application/json" } }) .then(res => { if (options.search) { // if searching for jokes, loop over the results res.data.results.forEach( j => { console.log("\n" + j.joke); }); if (res.data.results.length === 0) { console.log("no jokes found :'("); } } else { console.log(res.data.joke); } });
We added support for a new --search
the argument in the previous code. The code can use a different URL depending on retracting a random joke or searching for specific jokes. And in the conclusion, it must handle the results differently. You have to try this out!
> npm install -g . > hello -n me -s orange
Add Support for Secure Authorization with PKCE
An API requiring basic authentication is pretty straightforward. However, the situation changes if an API uses OAuth for authentication which is possible. PKCE i.e., Proof Key for Code Exchange is a nice solution for mobile and native applications for exchanging private keys with an authorization server. We are going to use the Okta API for this purpose. But it must be possible to adapt the code to your work with any OAuth 2.0 service you’re using. You can use Okta free of cost as it simplifies handling user authentication, social login, password reset, authorization, etc. Additionally, it can utilize open standards such as OAuth 2.0 for making integration seamless.
Create an Okta Application
Before beginning, please ensure that you have a free Okta developer account. So, install the Okta CLI and run okta register
for signing up for a new account. In case you already have an account then just run okta login
. After doing so, run okta apps create
. You can select the default app name, or change it as you like. Now choose Native and press Enter.
You can use http://localhost:8080/callback
for the Redirect URI and set the Logout Redirect URI to http://localhost:8080
.
Now you have to create a file with the name of .env
in the root of your Node.js CLI project. Then, open the file and add the information given below.
OKTA_ORG_URL=https://{yourOktaOrgUrl} OKTA_CLIENT_ID={yourClientID} OKTA_SCOPES="openid profile email" OKTA_REDIRECT_PORT=8080
Update the Node.js request Command-line Application
For supporting the PKCE authentication flow, your CLI application requires a few more libraries. In this blog, we will use hapi
creating a webserver to handle the authentication callback. dotenv helps to read configuration settings from the .env file. To launch the default browser for login, you will use open
. Additionally, you can use uuid
for generating a unique private key to exchange with the authentication server.
npm install @hapi/hapi@18.3 dotenv@8.0 open@6.3 uuid@3.3
Now you have to create a new folder in the root of the project with the name ofsrc
. Create a new file in this folder and name it authClient.js
. Then, add the below-mentioned code to the src/authClient.js
file.
"use strict"; const axios = require( "axios" ); const crypto = require( "crypto" ); const hapi = require( "@hapi/hapi" ); const open = require( "open" ); const querystring = require( "querystring" ); const uuid = require( "uuid/v1" ); const base64url = str => { return str.replace( /\+/g, "-" ).replace( /\//g, "_" ).replace( /=+$/, "" ); }; module.exports = ( { oktaOrgUrl, clientId, scopes, serverPort } ) => { if ( !oktaOrgUrl || !clientId || !scopes || !serverPort ) { throw new Error( "Okta organization URL, client ID, scopes, and server port are required." ); } // code verifier must be a random string with a minimum of 43 characters const codeVerifier = uuid() + uuid(); const redirectUri = `http://localhost:${serverPort}/callback`; const buildAuthorizeUrl = ( codeChallenge ) => { const data = { client_id: clientId, response_type: "code", scope: scopes, redirect_uri: redirectUri, state: uuid(), code_challenge_method: "S256", code_challenge: codeChallenge }; const params = querystring.stringify( data ); const authorizeUrl = `${oktaOrgUrl}/oauth2/v1/authorize?${params}`; return authorizeUrl; }; const getUserInfo = async accessToken => { try { const config = { headers: { Authorization: `Bearer ${accessToken}` } }; const url = `${oktaOrgUrl}/oauth2/v1/userinfo`; const res = await axios.get( url, config ); return res.data; } catch ( err ) { console.log( "error getting user info", err ); // eslint-disable-line no-console throw err; } }; const getToken = async code => { try { const request = { grant_type: "authorization_code", redirect_uri: redirectUri, client_id: clientId, code, code_verifier: codeVerifier }; const url = `${oktaOrgUrl}/oauth2/v1/token`; const data = querystring.stringify( request ); const res = await axios.post( url, data ); return res.data; } catch ( err ) { console.log( "error getting token", err ); // eslint-disable-line no-console throw err; } }; // Start server and begin auth flow const executeAuthFlow = () => { return new Promise( async ( resolve, reject ) => { const server = hapi.server( { port: serverPort, host: "localhost" } ); server.route( { method: "GET", path: "/callback", handler: async request => { try { const code = request.query.code; const token = await getToken( code ); const userInfo = await getUserInfo( token.access_token ); resolve( { token, userInfo } ); return `Thank you, ${userInfo.given_name}. You can close this tab.`; } catch ( err ) { reject( err ); } finally { server.stop(); } } } ); await server.start(); const codeChallenge = base64url( crypto.createHash( "sha256" ).update( codeVerifier ).digest( "base64" ) ); const authorizeUrl = buildAuthorizeUrl( codeChallenge ); open( authorizeUrl ); } ); }; return { executeAuthFlow }; };
The module of authClient.js
exports one function that accepts an object with the properties oktaOrgUrl
, clientId
, scopes
, and serverPort
. When you call this function, it will initialize the module with the configuration it requires. After the initialization, the function returns an object with exactly one function, executeAuthFlow
.

Now you have to update the CLI for using the authClient.js
module. So, create a a new file under bin
with the name of pkceLogin.js
. You have to add the below mentioned code to the pkceLogin.js
file.
#!/usr/bin/env node "use strict"; const chalk = require( "chalk" ); const dotenv = require( "dotenv" ); const authClient = require( "../src/authClient" ); // read in settings dotenv.config(); const config = { oktaOrgUrl: process.env.OKTA_ORG_URL, clientId: process.env.OKTA_CLIENT_ID, scopes: process.env.OKTA_SCOPES, serverPort: process.env.OKTA_REDIRECT_PORT }; const main = async () => { try { const auth = authClient( config ); const { token, userInfo } = await auth.executeAuthFlow(); console.log( token, userInfo ); console.log( chalk.bold( "You have successfully authenticated your CLI application!" ) ); } catch ( err ) { console.log( chalk.red( err ) ); } }; main();
In order to include another command in the bin
section, you have to update the package.json
file.
"bin": { "hello": "./bin/index.js", "pkce-login": "./bin/pkceLogin.js" },
You have to update the CLI applications that are installed globally.
npm install -g .
You are finally ready to test your new CLI authentication. When you have logged in, you will see in your console,
You have successfully authenticated your CLI application!
pkce-login
Conclusion
We hope that our blog on Node.js request helped you in understanding it. Thank you for reading our blog!