paint-brush
Optimizing User Input With Nest-Commander: A Quick Guideby@theBenForce
407 reads
407 reads

Optimizing User Input With Nest-Commander: A Quick Guide

by Ben ForceSeptember 27th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Use the `@Option` decorator with a parser function to accept arguments into a command. For more advanced features, create a `QuestionSet` and use it with the `InquirerService`.

People Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Optimizing User Input With Nest-Commander: A Quick Guide
Ben Force HackerNoon profile picture

In my previous article, you created a nestjs cli application. It was a very basic starting point that printed a cow saying a static message in the console.


But what if your users demand the ability to display custom messages? That’s what you’re going to add to this article. The new and improved application will display the same message by default or any string that you pass in with the --message argument.

Adding a Message Option

The easiest way to add an option is to add a parser function for a parameter and add the @Option decorator to it.


In the cow-say.command.ts file, add the following method to your CowSayCommand class.


@Option({
  flags: '--message <message>',
  description: 'The message we want to see the cow say',
})
parseMessage(value: string) {
  return value;
}

Decorating It

If you’ve used the commander library before, this should look familiar. The <message> tells commander that if the --message option is provided, the user doesn’t need to provide a parameter after it. If the value were required, it would be [message] instead.


The description parameter is used when the user displays help for a specific command. The description will be displayed in a column to the right of every available option.

The Parser

The @Option decorator is applied to a parser function, in this case parseMessage. The function takes in a string and needs to convert it to whatever type you want at runtime. If you had a --count <count> parameter, you’d need to convert a string to an integer.


Since the message should be a string, you just need to return it. Nothing fancy here.

Using the Options

To use the option, you need to accept two parameters in the run method. The first is an array of parameters that were passed in, and the second is an options object that includes all of the parsed options. Since you aren’t using the parameters you can just ignore it.


async run(_passedParams: string[], options: { message?: string }): Promise<void> {
  const message = options.message ?? 'Hello World!';

  console.log(cowsay.say({ text: message }));
}

Awesome, now if you run the program with a --message "Foo Bar" parameter, the cow will be saying, “Foo Bar.”

Using Inquirer

Using parsers like in the previous step works great for smaller commands. It has the advantage of being simple. But what if you would like to gracefully ask the user to enter any parameters they forgot to provide? For that, you can use the InquirerService.


The first thing you need to do is define the types of inputs that will be used for each parameter. That’s done with a class decorated with @QuestionSet and parsing methods decorated with @Question.


Create a cow-say.questions.ts file and add the following to it.

import { Question, QuestionSet } from 'nest-commander';

@QuestionSet({
  name: 'cowSay',
})
export class CowSayQuestions {
  @Question({
    type: 'input',
    name: 'message',
    message: 'What does the cow say?',
  })
  parseMessage(value: string) {
    return value;
  }
}


Now, add this class as a provider to your module.


...
import { CowSayQuestions } from './cow-say.questions';

@Module({
  providers: [CowSayCommand, CowSayQuestions],
})
export class CowSayModule {}


Now the message parameter needs to be updated to be mandatory in the command.


@Option({
    flags: '--message [message]',
    description: 'The message we want to see the cow say',
  })


Next, inject the inquirer service into the command.


constructor(private readonly inquiererService: InquirerService) {
  super();
}


Finally, update the run method and use the inquirer service to update the options parameter.


options = await this.inquiererService.ask('cowSay', options);

console.log(cowsay.say({ text: options.message }));


Now, when you run the command, if you don’t pass in the --message option the application will ask you to provide it.


❯ npm run start:cli   

> [email protected] start:cli
> ts-node src/main.ts

? What does the cow say? Mooooooo
 __________
< Mooooooo >
 ----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Summary

In this article, you expanded upon the basic NestJS CLI application created in the previous installment. You learned how to add arguments with an option parser function and used the @Option decorator. You also learned how to use the InquirerService to gracefully prompt users to enter missing parameters and integrate it into your command, enhancing user interaction.


Also published here.