Command Pattern

The command pattern is a design pattern in which the
command
object encapsulates the information required to perform an action or trigger an event at a later time. It is an an elegant approach for logging requests and initiating desired behavior.
In this article:
2
Create the Components that Command Patterns Use
The basic approach to creating a command is to create a table for the
command
object and implement the desired behavior in an event rule.
Use the following process to create a command:
Create a Table for the Command Object
Create a table to store request types, for example,
RequestCommand
. In most cases, you will also define a database-generated key. For convenience, you can use managed data for these tables.
Creating a table unlocks the software that is already oriented to RESTful database APIs:
  • Simplified API.
    Command requests pass parameters in JSON request objects, like conventional database-oriented APIs.
  • UI creation.
    For example, to test your command pattern. You can use Data Explorer.
  • Reporting.
    For example, to analyze the received requests, for example, volume, results. The arguments are captured naturally.
  • Problem diagnosis.
    For example, to see the
    partialResults
    .
In many cases, you will have more than one type of command to build. Consider the single-command-per-table and the multiple-commands-per-table approaches, which you can mix and match. The command table can be child of domain table, which provides you easy access to parent attributes. The multiple-commands-per-table approach can be useful where there is generic logic shared over command types.
Add Columns for Arguments
Add columns for each parameter, for example,
payload
and
amount
.
Add Columns for Administration
An advantage of this approach is that you can add columns to assist in administration. For example, you can aid in problem diagnosis by adding
datetime
or record
partialResults
.
Create an Event Rule for Desired Behavior
To effect the desired behavior, create an event rule. The
row
object provides access to the columns you have added.
For more information about how to create an event rule, see Event Rule Types.
Client Invocation: POST to Command Table
Clients invoke the command by POSTing to the
command
object (either the table or a custom resource built on it), with a request body consisting of the arguments. This is the same idea as POSTing a new customer, order, etc. In most cases, this will be a custom resource of the command table, to hide administration columns.
Example Command Patterns
The following are typical examples of the command pattern:
POST: http://localhost:8080/rest/default/mycommands/v1/RequestCommand
JSON: {"command":"giveRaise", payload:{"employeeID":1,"percentRaise": 0.10}}
Give Raise Pattern
The reactive logic tutorial illustrates one approach for giving raises (somehow a popular example), using URL arguments. You can also implement give raise with the command pattern. This example provides a useful audit of salary changes.
The
giveRaise
event rule in the
Sample
API sample is defined for insert on the
EmpRaise
table (a child of the
Employee
table), such as:
var employee = row.employee;
logicContext.touch(employee);
employee.salary = employee.salary * (1 + percentRaise);
logicContext.update(employee);
For more information about the reactive logic tutorial, see Logic Tutorial.
Alternatively, you can use the multiple-commands-per-table approach, so the code for the
giveRaise
event rule is:
if(row.command === 'giveRaise'){
var empID = row.payload.employeeID;
var percentRaise = row.payload.percentRaise;
var employee = logicContext.getBeanByPrimaryKey("employee", empID);
logicContext.touch(employee);
employee.salary = employee.salary * (1 + percentRaise);
logicContext.update(employee);
}
Event Sourcing Pattern
The event sourcing pattern is a straight-forward pattern that preserves transactional information. It inserts into a child table the change to the employee (parent) name by inserting a new row in the
empChanges
audit-like table.
Using the same data model, create a child of Employee called
EmpChanges
. Create a pipeline event for inserts into
EmpChanges
, such as:
var emp = row.Employee; //get Parent Object
logicContext.touch(emp);
if (row.name !== null) emp.name = row.name;
// etc for all attributes,
// or, create a shared lib routine that automates moving same-named attributes
logicContext.update(emp);
For more information about this pattern, see the Event Sourcing documentation and Martin Fowler's website.
Data Sync Request
In the previous examples, the transactions were about data that
Layer7 Live API Creator
directly manages. This is not always the case. Many applications integrate a source and target system. The source system POSTs a command request containing data to be sent to a target system.
The following example from the Business to Business (B2B) sample illustrates the solution. You start by defining locally the
SyncRequest
table, matching the columns (and child data, if any) from the source system. Then, you create a commit event rule to move this to the target, using the
ShipperAPIDef
resource that defines the mapping and transformation logic. The following code snippet shows the code for this commit event rule:
var transform = logicContext.transformCurrentRow("ShipperAPIDef");
B2B.sendToWebHook(transform, shipper.OrderChangeWebHook);
For more information about the B2B sample, including how you can extend your logic with table events, see B2B API Sample.
Wake-up Request
In some cases, the source system is passive, and does not POST requests to initiate integration. You can create a cron job that posts to the command table, for example,
PollRequests
. The
PollRequest
cron job queries the source system (perhaps writing results into command table administration columns). This can result in a list of rows. Since these rows do not correspond to tables in your schema, you must write code to move each attribute to a Post Request JSON.
Command Pattern Considerations
The following are considerations for using the command pattern.
Simplify Database Administration
In some applications, you might not have otherwise required a local database, such as with the Data Sync Request command pattern example. Creating a database might appear to be overhead, but you can set up an additional Derby database. You can migrate dev to production using MySQL database export, or, for Derby, copy the Derby folder, or create a export script with tools such as DbVisualizer.
Error Handling
When an error occurs, instead of rolling back the transaction, create a column for the result and have API Server intercept error conditions using error events. Rolling back the transaction removes the
command
object. This object can be helpful in diagnosing the failure.
For more information about how to create error events, see Pipeline Events.