Skip to content

Command Handlers

Adam Wolfe edited this page Aug 1, 2024 · 1 revision

Overview

Command handlers "do the work". Handlers are where you place the logic for your command and produce the console output.

Handler Definition

Suppose we have a command definition in our imperative configuration:

"definitions": [{
        "name": "hello",
        "description": "A sample command",
        "type": "command",
        "handler": "/path/to/handler",
}]

The handler, should be placed in directory /path/to/ with filename handler.ts.

Handler Module

The handler module must be a valid Node.js require()-able module that uses export default and implements the ICommandHandler interface:

export default class Handler implements ICommandHandler {
    public async process(params: IHandlerParameters): Promise<void> {
        params.response.console.log("Hello World!");
    }
}

Handler Parameters

Imperative invokes the handler's process method with IHandlerParameters. See the interface for detailed typedoc.

In summary, the handler parameter object contains:

  • arguments object (keyword value pairs that contain the values for the options specified by the user)
  • command response APIs (for producing messages)
  • Loaded profiles
  • The command definition document

Accessing Arguments

Suppose our command definition was formatted as such:

"definitions": [{
        "name": "hello",
        "description": "A sample command",
        "type": "command",
        "handler": "/path/to/handler",
        "options": [{
            "name": "my-opt",
            "description": "My option",
            "type": "string"
        }]
}]

We can access the value of my-opt in our handler through the arguments object:

export default class Handler implements ICommandHandler {
    public async process(params: IHandlerParameters): Promise<void> {
        params.response.console.log(params.arguments.myOpt);
    }
}

Notice that the option was transformed from kebab case to camel case. This is for programmer convenience, but the my-opt property is also present on the arguments object:

{
    "$0": "main.js",
    "_": ["hello"],
    "myOpt": "the value supplied by the user",
    "my-opt": "the value supplied by the user"
}

Producing Responses

If we look at our example handler:

export default class Handler implements ICommandHandler {
    public async process(params: IHandlerParameters): Promise<void> {
        params.response.console.log("Hello World!");
    }
}

We can see a console log message being issued. In order for imperative to properly format/handle command responses, you must use the response API provided to the handler. Do NOT use console directly. The response API contains methods for printing log, error, headers, and more. See the IHandlerResponseApi interface for detailed typedoc.

JSON Response

Imperative will automatically append the --response-format-json boolean option to every command. Users can specify this option to instruct imperative to produce the response in JSON format:

{
  "success": true,
  "message": "Some data is provided!",
  "stdout": "",
  "stderr": "",
  "data": {
    "moreData": "hello world!"
  }
}

You can populate the data and message properties via the IHandlerResponseApi See the interface for detailed typedoc.

Progress Bars

Handlers can create progress bars to display status/progress information to the user. For more information, see IHandlerProgressApi. See Implementing Progress Bars for details and examples of creating progress bars.