Menu

Ahoy! Parse ye Node.js command args with yargs!

April 20, 2015

Recently I was working on a code sample in Node.js and thought to meself, "T'wouldn't it be grand to support me some command-line args for this here..." or... something to that effect. So, with a quick Google off the port bow, I came across yargs.

Yargs be a node.js library fer hearties tryin' ter parse optstrings. With yargs, ye be havin' a map that leads straight to yer treasure! Treasure of course, being a simple option hash.

Yargs makes it easy to support command-line arguments for Node.js application. Check out the LeanKit search sample application I created that uses yargs.

Here be a quick example for ye

Imagine we plan to create our own version of curl named "jurl", implemented in Node.js specifically for REST and JSON. Our first pass at the arguments we want to support might look like this:

var options = require( "yargs" )
 .usage( "Usage: $0 <url> [-u \"username\"] [-p \"password\"] [--post] [--data \"{key:value}\"]" )
 .command( "url", "URL to request", { alias: "url" } )
 .required( 1, "URL is required" )
 .option( "u", { alias: "user", demand: false, describe: "Username", type: "string" } )
 .option( "p", { alias: "password", demand: false, describe: "Password", type: "string" } )
 .option( "d", { alias: "data", describe: "Data to send as JSON", type: "string" } )
 .option( "get", { describe: "Use HTTP GET", type: "boolean" } )
 .option( "post", { describe: "Use HTTP POST", type: "boolean" } )
 .option( "put", { describe: "Use HTTP PUT", type: "boolean" } )
 .option( "del", { describe: "Use HTTP DELETE", type: "boolean" } )
 .help( "?" )
 .alias( "?", "help" )
 .example( "$0 https://example.com/api/posts", "Get a list of posts" )
 .example( "$0 https://example.com/api/posts --post --data \"{ 'title': 'Avast ye!', 'body': 'Thar be a post hyar!'}\"", "Create a new post" )
 .epilog( "Copyright 2015 ReverentGeek" )
 .argv;

// Get the URL from the first parameter
var url = options._[ 0 ];

// Make "get" the default if no verb is specified
if ( !options.get && !options.post && !options.put && !options.del ) {
 options.get = true;
}

console.log( "url:", url );
console.log( "options:", options );

Take a look at the command-line help yargs creates for ye.

$ node jurl --help
Usage: jurl <url> [-u "username"] [-p "password"] [--post] [--data
"{key:value}"]

Commands:
  url    URL to request

Options:
  -u, --user      Username                                              [string]
  -p, --password  Password                                              [string]
  -d, --data      Data to send as JSON                                  [string]
  --get           Use HTTP GET                                         [boolean]
  --post          Use HTTP POST                                        [boolean]
  --put           Use HTTP PUT                                         [boolean]
  --del           Use HTTP DELETE                                      [boolean]
  -?, --help      Show help

Examples:
  jurl https://example.com/api/posts          Get a list of posts
  jurl https://example.com/api/posts          Create a new post
  --post --data "{ 'title': 'Avast
  ye!', 'body': 'Thar be a post hyar!'}"

Copyright 2015 ReverentGeek

Running the given sample prints the following to the console.

$ node jurl http://example.com/api/posts
url: http://example.com/api/posts
options: { _: [ 'http://example.com/api/posts' ],
  get: true,
  post: false,
  put: false,
  del: false,
  '$0': 'jurl',
  u: undefined,
  p: undefined,
  d: undefined,
  '?': undefined }

Hoist the mizzen, sail forth and blast ye command ARRRRGS to smithereens!

Comments

5 archived comment(s) from this site's previous comment system. These are read-only — join the discussion above.

  1. Justin

    Nice example. 'url' is not a command though and it's listed as a command in the help output.

    I'm looking for an example of yargs usage where there are multiple commands… and by default if no command is given, I want to fall back to --help output. Do you happen to know how to do this?

  2. David Neal

    Hi Justin,

    In this example, the url command is any text you might type in as the first argument. You can certainly have more than one. I think it's a good practice to have arbitrary input arguments first, then followed by any command-line switches.

    There are a couple of ways you can trigger help output. One is to make at least one of the commands required. Another is to check the length of the arguments, and use yargs.showHelp(). Here's an example:

    var yargs = require( "yargs" );
    var options = yargs
    .usage( "Usage: $0 <url> [-u \"username\"] [-p \"password\"] [--post] [--data \"{key:value}\"]" )
    .command( "url", "URL to request", { alias: "url" } )
    // .required( 1, "URL is required" )
    .option( "u", { alias: "user", demand: false, describe: "Username", type: "string" } )
    .option( "p", { alias: "password", demand: false, describe: "Password", type: "string" } )
    .option( "d", { alias: "data", describe: "Data to send as JSON", type: "string" } )
    .option( "get", { describe: "Use HTTP GET", type: "boolean" } )
    .option( "post", { describe: "Use HTTP POST", type: "boolean" } )
    .option( "put", { describe: "Use HTTP PUT", type: "boolean" } )
    .option( "del", { describe: "Use HTTP DELETE", type: "boolean" } )
    .help( "?" )
    .alias( "?", "help" )
    .example( "$0 https://example.com/api/posts", "Get a list of posts" )
    .example( "$0 https://example.com/api/posts --post --data \"{ 'title': 'Avast ye!', 'body': 'Thar be a post hyar!'}\"", "Create a new post" )
    .epilog( "Copyright 2015 ReverentGeek" )
    .argv;

    // Check to see if no args were passed
    if ( options._.length === 0 ) {
    yargs.showHelp();
    } else {
    // Get the URL from the first parameter
    var url = options._[ 0 ];

    console.log( "url:", url );

    // Make "get" the default if no verb is specified
    if ( !options.get && !options.post && !options.put && !options.del ) {
    options.get = true;
    }
    }

    console.log( "options:", options );

    Hope this helps!

  3. Justin

    Thanks David! Ye the simplest way seems to be:


    .required( 1, 'At least one command is required')

    :)

  4. dissertation writing help

    Seems pretty effective to consider in using Yargs into someone's work especially if they wanted to build some new ideas and techniques that will totally be a perfect advantage for their future. For sure, they can be able to come up with a better output from this idea that you give.

  5. Nathaniel Perez

    hi David,

    do you know whether there is a way of configuring usage with more than one possible command
    let's say my script is named app.js and can log in and out a web session.
    so I have 2 possible commands:
    node app.js login --user "user" --pw "password"
    or
    node app.js logout.
    How can i constrain this in usage?

    Thank you
    Nathaniel