REST is all the rage. It provides a networked approach to exposing data and services, both internally within a company and to partners. Here, we explore a novel approach to providing a RESTful API to a set of existing commands.
Business Problem: expose Commands via REST
Many organizations have made considerable software available through Unix-like commands. Imagine an Enterprise, well, the Enterprise, that wishes to provide RESTful APIs to commands like:
OrderSickLeave <crew-member>, <duration>
IncreaseSpeed <warp-factor>, <emergency-reason>
SelfDestruct <authorization-code>
- ? hundreds of them?
Each of these commands is backed by some software, say a Java Class of some sort.
They?d like to publish this functionality, as follows:
- Restify ? provide a RESTful API for each command. The REST attributes are the command arguments, above
- Validate ? before the commands is issued, validate the arguments (does
<crew-member>
exist, is the<duration>
a positive number, etc) - Secure ? ensure the commands are available as appropriate
Background: Espresso creates RESTful API for SQL data
Espresso creates RESTful APIs, principally for SQL data. Some key functionality is described below.
API Creation
You connect Espresso to a database, and it creates a RESTful endpoint for each table, view and Stored Procedure. The API supports the usual RESTful operations of Get (including filters based on HTTP arguments), and update (Put, Post and Delete).
Validation Rules
You can specify validation rule expressions that are automatically executed on update requests. For example, you might specify a rule that balance <= creditLimit
.
Validation rules are part of the larger notion of business logic, which includes computations (the balance is the sum of the unpaid order amounts). Computations can chain, and validations work over computed data, so you can solve remarkably complicated problems with a few simple rules.
Extensibility
Espresso creates a server-side JavaScript Domain Object for each table, providing access to attributes (customer.balance
), and persistence (customer.save()
).
The objects encapsulate their integrity in two ways:
- Rule Invocation ? update requests trigger the relevant validation / computation rules
- Events ? you can also associate server-side JavaScript event handlers with a table. These fire as update requests are processed
The Event handlers can invoke anything in the JVM, such as jar file code you can load into Espresso, other RESTful services, etc.
Background: Command Pattern
Imagine a word processor, providing functionality to make a string of selected text bold, another bit of functionality for italics, and so forth. Now imagine we wish to provide Undo functionality. Not possible unless we save the commands.
So, the Command Pattern emerged:
- create a class for each Command
- creating an instance ?does? the command (e.g., make text bold), where the constructor arguments provide the necessary information (text start, length)
- maintain an ordered list of commands (object instances)
- require the Command Classes to provide an Undo method to reverse the effects of the constructor (e.g., remove the bold)
Database Adaption: insert logic on a Request Table
We can see this same pattern in database applications, where we wish to keep a record of transactions. For example, instead of just changing a salary (and forgetting who, when, old values etc), we create a SalaryAction(employeeId, raisePercent)
. We can think of this as a Request Table.
The logic on the SalaryAction
table might give the raise, but also validate (is the percent too big? is the resultant salary out of range?), and record who, when etc.
Restify Commands with Request Tables
So we can combine these notions:
- Create a database with table for each Command (OrderSickLeave, IncreaseSpeed, etc), with columns for command arguments. We can also provide columns for admin data (date executed, etc)
- Leverage Espresso to Restify these
- Declare Validation Logic
- JavaScript table events execute the command
We can now use this approach to Restify our Enterprise commands, as described below.
Command Requests Database
The lower 3 tables are the Request Tables. They each have Foreign Keys to the Crew table, simply identifying the source of the request (this is optional).
Load into Espresso
We next connect Espresso, which discovers these tables and creates a Default RESTful API to them. We can view it in a test tool immediately:
We can also define a Custom API, exposing just the elements we wish:
Validate Command Parameters
The following rules apply to Posts against our Command Request tables. Here we ensure that the IncreaseSpeed request has
- a argument (attribute) for
warpFactor
, - that it be between 0 and 10, and
- that the optional
emergencyReason
parameter is supplied if thewarpFactor
exceeds 8
Live Browser ? view, post data
You can use the API tool, or this automatically constructed app:
Invoke existing code
Finally, we add server-side JavaScript logic (stubbed here) to execute our command. This would execute existing code in a loadable jar.
Conclusion: 4 hour project
This project was completed in about a half a day.