Creating APIs‎ > ‎Logic‎ > ‎

Logic Execution

Live API Creator executes your business logic in response to REST POST/PUT/DELETE requests. Use the information on this page to learn how the server operates so you can debug your API project.

Prerequisites:
  • You understand the JavaScript object model.
For more information about the JavaScript object model, see Customize your API.

Shown conceptually in the following video, this page shows how to use rules, how rules work, and how rules integrate with events.

Rule Operation

Usage Overview

API Creator uses them rules you declare to process RESTful updates.

Connect and Declare Rules

When you create an API project and connect to your database, Live API Creator creates a JavaScript Object Model. You can think of these as Object-Relational Mapping (ORM) objects: they provide access to attributes, related objects, and persistence. They also expose update events you can handle in JavaScript.

Many ORMs require tedious synchronization between your schema and objects. The use of JavaScript means these objects are dynamic and require no code generation. The objects automatically stay in sync with your model.

But the ORM objects are much more. They are logic aware. That is, they encapsulate both declarative rules, and conventional JavaScript events. You might think of these are declarative persistence objects. The declarative rules are expressions for deriving/validating data. The first validation rule ensures that the balance does not exceed the credit limit (else the transaction is rolled back), and the second rule computes the balance by summing the related Orders:

Validation: return row.CreditLimit >= row.Balance
Derive Balance as Sum(Orders.AmountTotal where ShippedDate === null)

The expression operands are derived from the schema: tables, columns and foreign key relationships. You enter rule expressions using a combination of forms and server-side JavaScript functions (providing if/else logic, access to libraries, etc). You can execute these rules. After you have entered the rules, RESTful update processing calls the rules, orders the rules, and reads/writes the data.

RESTful Update Processing

The following sub-sections explain how API Creator processes update requests.

Request Events

API Creator raises request pre-events. It raises a request event once for the entire update request. Your JavaScript can inspect/alter the JSON request body.

For more information about request events, see Event Handlers.

Resource/Object Mapping

You can define multiple custom resources on the same underlying base table. These can represent projects and aliases of table columns. Integrity demands that the base table logic is enforced regardless of the resource used.

Resource/object mapping is required to map the resource objects onto their respective row objects, including column name de-aliasing and materialization of columns not projected (sometimes called "hydrated"). This means that the declarative and event logic is always dealing with a full row, and that logic is shared over all custom resources. This requires a database read, with concurrency control supplied by the DBMS.

So that you can define logic based on data changes, Live API Creator builds the following row objects:

      • row. This object reflects client changes from JSON, and all logic processing.
      • oldRow. This object reflects the row before the transaction started. This object is from the database read.

Optimistic locking checks are performed to ensure that updated rows will not overlay the updates of other users. This check is on a time-stamp field if provided, otherwise it is the hash of all attributes in the resource row.

For more information about row objects, see Row Objects.

Generated Primary Key Handling

Databases support system-generated primary keys. There are special requirements when processing JSON POSTs that include child rows for such tables, such as the items for an order. API Creator must "stamp" the generated order# into each item. It does this prior to logic execution and when it performs managed parent is performed.

When using a resource with nested children (Customer contains Orders, contains Items), the ability to POST (insert) a new Customer, Order, and Items in one transaction can only be done when the primary key of the parent (Customer or Orders) can be propagated down to the child (e.g. Orders or Items).

For more information:

Logic Phase Processing

API Creator processes each submitted row in the order it receives them, as follows:

  1. It calls early row events, supplied with row, oldRow and logicContext. Your event can inspect/alter the row before rules fire. For example, you might want to compute network-unique primary keys.
  2. It executes (only) those rules whose dependent row data has changed (based on comparing row vs. oldRow). It computes the rule execution order based on rule dependencies, discovered by automatic rule parsing. The rule updates the row (state), so it is visible to ensuing rules.
  3. It executes row events so that you can do whatever is not expressed in declarative logic. For example, send email, post data to other systems, and credit card checks. You are passed row, oldRow, and logicContext. The effects of rule changes are visible in your row objects.
    Note: 
    You can alter the row, but you must 
    resave it.
    For more information about logic events, see Logic Event Rule Types
    .
  4. If the logic has altered data referenced by rules in related objects, it instantiates rows for them and invokes their logic. For example, altering OrderTotal updates the related customer's balance, whose rules would verify the CreditLimit. This is an efficient one-row update, not an aggregate query.
Note: One transaction is used for all updates of a given request, both rows from the client, and chained updates (last step, above).  Rows are buffered into the write-cache so that multiple updates to the same row (for example, many line items may adjust the Purchaseorder amountTotal.

Commit Phase Processing

The write-cache is flushed to the database at the end of the transaction, after all rows have been processed. In addition to the flush, there is a important logic provision.

Your logic specifications for validations and events can stipulate that they run during normal per-row execution or be deferred until commit. If you elect that they run during normal per-row execution, such logic is executed just prior to transaction flush. The logic phase has been completed, so all the logic for all the rows are visible in your row objects.

For example, you want to ensure Purchase Orders have at least one line item. You can define a Purchaseorder.item_count, along with a Purchaseorder validation that item_count > 0

While a good approach, this would fail. Why? API Creator processes the Purchaseorder insert first, before Line Items. At this point, the count is zero (0), so the validation fails. Instead, you can commit validations and events that need to operate on the end-result of logic processing for all the rows in the entire transaction.

For more information:

Response Events

API Creator raises request post events. You can alter the response message or perform other functions such as logging.

Forward Chaining

With forward chaining, if you change a referenced value, API Creator recomputes the derived referencing attributes. The term chaining correctly infers that a derived attribute (for example, Purchaseorder.amount_total) is itself referenced in another derivation (Customer.balance). API Creator tracks these references and performs the forward chaining, automatically.

For formulas (for example, price * quantity), this entails evaluating the expression (though see ordering, in the following sections). It is more complicated for dependencies and multi-table derivations.

Orderingxx

Columns dependent on changed columns may themselves have interdependencies. For example:

a = b + x
b = x + 2

It is clear that a depends on b, so if x is altered, we must recompute b before we recompute a. You can state these rules in any order. You can change the rules during maintenance, without concern for ordering.

Parent Adjustment

Continuing our Customer.balance example, imagine a simple update where a Purchaseorder is marked paid. We need to recompute the new balance.

A dreadful approach would be to issue a SQL Sum query to add all the existing orders. In general, there could be thousands! And worse, this could be chained, where the summed attributes depend on further summed attributes. That is, in fact, just the case here: the Purchaseorder.amount_total is itself a sum of the Lineitem.amount. This is a significant performance factor; ORM products are often blamed for poor performance due to excessive use of chained aggregate queries.

API Creator adjusts the parent sum by the change in the child. The result is a one-row update (unless it was pruned).

Child Cascade

There are analogous considerations where the client alters a parent attribute referred to in child logic (for example, a formula). When this occurs, Live API Creator visits each related child to run the dependent logic. This may update the child, and trigger further adjustment / cascade processing to other related data.

For more information about formulas, see Formula Rule Type.

Multi-table chaining

Adjustment and cascade-processing make updates to related data. API Creator often issues SQL updates for data beyond that originally sent from the client. This is a natural consequence of your logic and exactly what business logic is supposed to do. These triggered updates are subjected to the full logic analysis/chaining process, so will often result in still other updates. For example, consider a simple update to a Lineitem.quantity:

  • Lineitem.amount is derived as price*quantity, so is recomputed.
  • Purchaseorder.amount_total is derived as Sum(Lineitem.amount), so it is recomputed (adjusted).
  • Customer.balance is derived as Sum(Purchaseorder.amount_total where Paid = false), so is is adjusted.

The customer logic re-evaluates the credit limit check - if not passed, the entire transaction is rolled back, and an exception is returned to the client.

Logic Re-execution

Observe that chaining means your logic may be executed more than once on the same row multiple times within a transaction. Consider a transaction comprised of a purchase order with multiple Line Items. The purchase order logic is clearly executed on insertion. Now consider that each Line Item would adjust the Purchase Order's amount_total. This re-executes the purchase order logic, now as an update. Your logic can determine nestLevel and initialVerb by way of the LogicContext object.

For more information about the LogicContext object, see The logicContext Object.

Reactive Programming vs Conventional Procedural Programming

You can make the following key observations about some fundamental characteristics that distinguish reactive programming from conventional procedural (imperative) programming:

  • No Control flow. API Creator invokes the rules and only in reaction to actual changes. You do not order their execution. Rules are bound to the data, not a specific use case, so they apply to all in-coming transactions. In other words, the logic automatically processes the following transactions:
    • Order inserted - balance increased
    • Order deleted - balance decreased (if not paid)
    • Order unshipped - balance decreased
    • Order shipped - balance decreased
    • Order amountTotal changed - balance adjusted
    • Order reassigned to different customer - balance increased for new customer, decreased for old
    • OrderDetail inserted - obtain price, adjust Order and Customer (and check credit)
    • OrderDetail Deleted - reduce Order and customer totals
    • OrderDetail Quantity increased - adjust Order and Customer (and check credit)
    • OrderDetail Product Changed - obtain price, adjust Order and Customer (and check credit)
    • OrderDetail Quantity and Product Changed - obtain price, adjust Order and Customer (and check credit)
    • Customer CreditLimit changed - check credit

This results in a meaningful improvement in quality. Reactive programming eliminates of an entire class of programming error (for example, balance checked when adding an order, but overlooked on unshipping an order).

  • Elimination of Boilerplate code. In a conventional approach, the bulk of your code is change detection, change propagation, and persistence handling (SQL commands). Reactive programming automates this. The logic is executable:
    • ORM creation. Code is saved in the JavaScript object model.
    • Change detection. Most of the alternative code is determining when to propagate updates by detecting changes. This is eliminated in the declarative-reactive approach.
    • SQL (caching). SQL handling is tedious. Rules automate the SQL, including the underlying services for caching.

Simple Example: Check Credit

In our example, a solution of Check Credit is devised. Building on the previous two rules:

Validation: return row.CreditLimit >= row.Balance
Derive Customer.Balance as Sum(Orders.AmountTotal where ShippedDate === null)
Derive Orders.AmountTotal as Sum(OrderDetails.Amount)
Derive OrderDetails.Amount as row.Price * row.Quantity // JavaScript Expression
Derive OrderDetails.Price as copy(Product.Price)

This represents the complete, executable solution, that includes:

  • Ordering. You can alter the previous rules in any order since they are automatically ordered per dependency management.
  • Re-use. API Creator applies the rules to all incoming transactions, automatically invoking the previous (relevant) logic.
  • Automatic Persistence. API Creator processes incoming transactions by providing the SQL. Adjusting a quantity automatically reads/adjusts the Orders and Customer rows, and it does so efficiently (a one-row update, not an expensive select sum query).

Common Logic Patterns

This simple "Balance < CreditLimit" example illustrates one of the most common logic patterns, validating a rollup/constrain derived result. Other examples of the pattern include:

  • Rollup employee salaries to department, constrain to budget.
  • Rollup departments, constrain to budget.
  • Rollup Student Course Credit, constrain to max for student, max for course.
  • Compute Product Price from the sum of the Component Parts (nested).
  • Compute Event GiftsAmount from sum of EventGifts.

A similar pattern is Existence Checks: validations on [qualified] counts, such as an Order must have items and Department must have employees.

For more information about the common logic patterns, including validate a sum (rollup) and existence checks, see Learning Rules.

Business Perspective: Agility, Transparency, and Quality

Declarative logic is more expressive than imperative code. The previous five lines of logic equates to over 200 lines of triggers, or 500 lines of Java. It's also far more readable, in fact understandable, to business users.

In an industry where we walk over hot coals for a 30% gain, this is a 40X improvement in expression factor. You can deliver update business logic 10X faster using rules. Removing boilerplate code and automatic re-use drives this compression factor.

JavaScript When you Need It

The JavaScript object model provides for row events which you can handle in JavaScript. The following image shows an example from the Add Payment example:

For more information about the Add Payment example, see Reactive Logic Tutorial.

More Information

For more information: