Skip to content

Setup

To process a command posted from a client, a command handler must be created. This is very similar to how endpoints and tasks are added to a project before a client application can use them.

Note

Setting up command handlers in a project is only required when adding custom commands.

Setting up command handlers requires the following steps:

  1. Create the command_handlers folder and copy the __init__.py to it.
  2. Import command handlers in the project's init.
  3. Create a handler.
  4. Write some tests!

1. Create the command_handlers folder and copy the __init__.py to it

Create a folder named command_handlers in the solution or package, next to the endpoints folder.

Example:

cd solution-test/solution_test
mkdir command_handlers

Add the following __init__.py file to the created folder.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# solution-test/solution_test/command_handlers/__init__.py
import importlib
import logging
import pkgutil

logger = logging.getLogger(__name__)


def register_command_handlers():
    for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
        if module_name.endswith("test"):
            continue
        module_fullname = "{}.{}".format(__name__, module_name)
        logger.info("Loading {}".format(module_fullname))
        importlib.import_module(module_fullname)

Import command handlers in the project's init

Next step is to import register_command_handlers when the solution or package is initialized.

Add the following lines to the end of the project's __init__.py file. Eg. solution-test/solution_test/__init__.py, given that the Lime Project is named solution-test.

try:
    from .command_handlers import register_command_handlers  # noqa
except ImportError:
    logger.info(
        "solution_test doesn't implement any custom command handlers"
    )

(remember to replace solution_test with the project name)

Create a handler

Create a file named as the command name and place it in the command_handlers folder and add the command handler function to it.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# solution-test/solution_test/command_handlers/command-name-here.py
from limepkg_server_commands.commands import (
    Command,
    CommandContext,
    CommandResult,
    commandhandler,
)

@commandhandler("command-name-here")
def handle_command_name_here(ctx: CommandContext, command: Command) -> CommandResult:
    return CommandResult.ok(command)

Attention

Command names are global and need to be unique. Two packages can't both register the command name send-sms so pick a name that uses the solution or package name.

Report errors

Return CommandResult.fail(...) when a command can't be executed. Its message is returned to the client.

You can also raise one of these exceptions from limepkg_server_commands.commands. Their messages are returned to the client:

  • ParameterError when the command's parameters are invalid. The error gets the PARAMETER code.
  • CommandError for any other error. The error gets the OTHER code.

The messages of all other exceptions, including builtin exceptions such as ValueError, are never returned to the client, since they can contain internal details such as SQL. They are logged and replaced with "An internal error occurred while executing the command".

Validate ids

Validate ids from command parameters with parse_id from limepkg_server_commands.commands before using them in a query. It returns the id as an int and raises a ParameterError if the value isn't a positive integer.

from limepkg_server_commands.commands import parse_id

id = parse_id(command.parameters.id)

Write some tests!

The example handler show how a pytest fixture can be used to "send" a command batch from a test case.

Back to top