RESO Transport Workgroup

RESO Validation Expressions

RCP 19
Version 1.0.0
Authors Joshua Darnell (RESO)
Paul Stusiak (Falcon Technologies)
Specification View on GitHub
Status RATIFIED
Date Ratified December 2023
Dependencies Validation Expression grammar
Data Dictionary 1.7+
Web API 2.0.0+
Related Links DD Wiki 1.7
Data Dictionary Spreadsheet



RESO End User License Agreement (EULA)

This End User License Agreement (the “EULA”) is entered into by and between the Real Estate Standards Organization (“RESO”) and the person or entity (“End User”) that is downloading or otherwise obtaining the product associated with this EULA (“RESO Product”). This EULA governs End Users use of the RESO Product and End User agrees to the terms of this EULA by downloading or otherwise obtaining or using the RESO Product.


Table of Contents


Introduction

Business rules are an important, but challenging, topic and come in many forms. There are validation rules (like requiring list price being greater than 0) and process rules (such as requiring a contract date when a listing is sold). There are also display rules, such as additional elements being shown and/or required based on the current state of a record.

These rules come into play whenever a record is created, updated, or deleted. Display rules can also apply to readonly access to that data in an API or UI.

The goal of this specification is to provide a machine-executable business rules grammar, as well as a transport mechanism to convey rules. Another goal is that the rules themselves be human friendly.

Executable business rules also provide a way to document a system’s rules in a way that’s both vendor and technology agnostic.


Section 1: Purpose

The ability to express and exchange machine-executable business rules has several uses. For example, providing immediate feedback to users when adding a record to a system from their own frontend of choice, without calling back to a vendor system for validation. They can also be used in back-office systems so they can push records back to an MLS or other system for publication (disconnected edit).

The RESO Web API is built on OData, which does not provide machine-executable rules at this time. However, this is something RETS previously offered.

After much discussion and several onsite meetings during 2016-2018, the community felt the best direction was to carry the work done in RETS forward to the RESO Web API. It had a few issues that needed to be addressed, as well as a need for a transport mechanism, but the grammar presented in this specification should mostly have backwards compatibility with what had come before for those who might have implemented it.

While there is still more work to do, such as the addition of a scope resolution operator to support rules for expanded data elements and new functions and special operations, it will be addressed in a future version.


Section 2: Specification

This specification consists of the following:

Section 2.1: Validation Expression Language

The RESO Validation Expression Grammar is used in conjunction with a data structure of FieldName, RuleAction, RuleExpression tuples to provide an ordered list of instructions that can be used to convey business rules in a system independent way.

These rules are intended to be written from the perspective of the business object being validated, such as a listing record in the Property Resource, and would be run as-needed before the client sends the record back to the system using the RESO Add/Edit specification.

For a client running the rules locally, making a change to the StandardStatus field would trigger rules relevant for that field (along with any related rules).

Expressions for a given ruleset MUST be evaluated in the order that they appear in the RuleOrder field.

While all rules may be executed each time data changes, clients SHOULD try and optimize execution so that only rules related to a given change are fired rather than all of them. There are a number of techniques that can be used to accomplish this, such as instruction scheduling or the Rete algorithm.

Rule optimization is beyond the scope of this document, but it’s helpful that there are existing techniques to address it.

Section 2.1.1: Actions

The following actions are defined by this specification:

Keyword Type Purpose
ACCEPT BOOLEAN If the expression is true, the field value is considered accepted without further testing. Immediately following SET expressions MUST be executed. If the expression is false, following validation expressions MUST be executed. If the expression is ERROR (evaluation failed) in client, the client SHOULD act as if the field was accepted, allowing the server to make the final decision.
REJECT BOOLEAN If the expression is true, the field value is considered rejected without further testing. Subsequent SET expressions MUST NOT be evaluated. If the expression is false, following validation expressions MUST be executed. If the expression is ERROR, evaluation failed in client, the client SHOULD act as if the field was accepted, allowing the server to make the final decision.
WARNING BOOLEAN If the expression is true, the client should show a warning message to the user, and if the warning is okayed by the user, include a Warning-Response in the UPDATE request. If the user does not okay the warning, the field is considered rejected and following SET validation expressions MUST NOT be evaluated.

If the expression is false, the following validation expressions MUST be evaluated.
SET TYPEOF(Exp) The following expression is evaluated and the result stored in the designated field.
SET_DEFAULT TYPEOF(Exp) This expression MUST be executed ONLY when a NEW record is created. Supersedes the default value as indicated in the Update Metadata.
SET_REQUIRED BOOLEAN Expressions of this type are designed to evaluate an expression and set the field that the rule is applied on to Required if the expression returns true and to Non Required if the expression returns false.
SET_READ_ONLY BOOLEAN Expressions of this type are designed to evaluate an expression and set the field that the rule is being applied on to Read Only if the expression returns true and to updatable if the expression returns false.

The client application is expected to lock the value of the field the rule is being executed on to the value at the time the SET_REQUIRED expression is evaluated.
RESTRICT_PICKLIST LIST(CHAR) Expressions of this type are designed to return one or more lookup values that are to be removed from the lookup list that is defined for the field the rule is being executed on. This is always the entire set of values to remove from the lookup.

In other words, if this returns a blank list or .EMPTY., the entire set of lookup values is to be displayed.

The value of this expression MUST be a LIST, rather than Exp.

All members of the list MUST be of the same data type as that of the field the rule is being executed on.
SET_PICKLIST LIST(CHAR) Expressions of this type are designed to return one or more lookup values that are to be used in the lookup list defined for the field the rule is being executed on.

The value of this expression MUST be a LIST, rather than Exp.

Every member of the list MUST exist in the lookup list as defined in the metadata for the field the rule is being executed on.
SET_DISPLAY BOOLEAN Expressions of this type are designed to allow a client to make fields visible or invisible based on the evaluation of an expression. The result of this expression has no effect on whether a field is READ ONLY or not.

Section 2.1.2: Validation Expressions

For detailed information, please see the Validation Expressions grammar.

This section contains examples to help illustrate how Validatine Expressions can be used.

Basic Examples

Arithmetic Operators

3 + 5

1 * 3 + 2 - 5

FIELD_NAME

To get current value of any field, use the Data Dictionary name: ListPrice

Bracketed FIELD_NAMEs

Supported for backwards compatibility with RETS: [ListPrice]

Simple Comparisons

ListPrice > 0

Access the Last Value of a Field

LAST Status != 'Sold'

Field Change Detection

Returns true if ListPrice has changed.

ListPrice != LAST ListPrice

Function Calls

foo()
foo('bar', 'baz', 42)

Functions MUST NOT use any FIELD_NAMEs or reserved words.

Lists of Expressions

(ListPrice, Status, 3+5, LAST Status, (1, 2, 3))

Complex Expressions with Grouping

ListPrice > 5.01 .AND. (1, 2, 3) .CONTAINS. 3 .OR. (Status .IN. ('Active', 'Pending') .AND. .MEMBER_MLS_SECURITY_CLASS. != 'Admin')

Which parses differently than

ListPrice > 5.01 .AND. (1, 2, 3) .CONTAINS. 3 .OR. Status .IN. ('Active', 'Pending') .AND. .MEMBER_MLS_SECURITY_CLASS. != 'Admin'

Collection Support

The RESO Validation Expression proposal added support for LIST() and SET().

These functions take 0 or more items where 0 items would mean an empty list or set.

Expression Result Comments
LIST(1, 2, 2, 3) LIST(1, 2, 2, 3 Duplicate items are preserved
SET(1, 2, 2, 3) SET(1, 2, 3) Duplicate items are removed


List and Set Difference, Intersection, and Union

This proposal also adds support for the following collection operators:

Which are intended to produce types in the following manner:

These special functions require at least two arguments of type LIST() or SET():

Expression Result Comments
DIFFERENCE(LIST(1, 2, 3), LIST(1, 2)) LIST(3) Collection operators require two or more LIST() or SET() arguments.
UNION(LIST(1, 2), SET(3)) LIST(1, 2, 3) Arguments of type LIST() are converted to SET()
INTERSECTION(SET(DIFFERENCE(LIST(1, 2, 3), SET(1))), SET(2)) SET(2) Since the return type of collection operators is SET() or LIST(), they can be composed

Section 2.2: Rules Resource

The Validation Expression grammar itself is not enough to compute rules. Additional information is needed.

The Rules Resource has been created in Data Dictionary 1.7+ to transport business rules.

At a minimum, these consist of the following:

Example: Update PurchaseContractDate when Listing is Closed

FieldName RuleAction RuleExpression
PurchaseContractDate SET IIF(LAST StandardStatus != 'Closed' .AND. StandardStatus = 'Closed', #2023-12-04#, NULL)

It’s also important that each rule contains human-friendly messages describing the outcome, when appropriate.

Rule Ordering

Rule ordering is important. Dependent rules MUST be executed in the order appropriate for their dependencies.

Consider the basic operations:

a = 1
b = 1 + a
c = a + b

If a = 1 isn’t executed first, then the second instruction will throw an error and the output won’t be available to the assignment of c.

However, if we had another expression d = 0, it could be executed in any order since there are no dependencies on any of the other items.

The Rule Resource includes a RuleOrder property so ordering may be preserved.

Rule Versioning

Sometimes it might be necessary to communicate that a given rule has changed.

The Rules Resource providers the Rule Version for these scenarios.

Filtering by FieldName and RuleAction

Consider the case where a client is interested in rules that might reject changes to ListPrice.

These can be retrieved using the following request to the Rules Resource:

REQUEST

GET /Rules?$select=RuleKey,FieldName,RuleAction,RuleExpression,RuleWarningText,RuleVersion&$filter=FieldName eq 'ListPrice' and RuleAction eq 'REJECT'

RESPONSE

{
  "@odata.context": "/Rules?$select=RuleKey,FieldName,RuleAction,RuleExpression,RuleWarningText,RuleVersion&$filter=FieldName eq 'ListPrice' and RuleAction eq 'REJECT'",
  "value": [{
    "RuleKey": "abc123",
    "FieldName": "ListPrice",
    "RuleAction:": "REJECT",
    "RuleExpression": "ListPrice GT LAST ListPrice * 2",
    "RuleWarningText": "ListPrice was greater than two times the original list price. Are you sure?",
    "RuleVersion": "1.234"
  }]
}


Section 3: Certification

Testing rules consists of the following steps:

Certification tools will be developed so a user can perform all these steps in an interactive manner through both a CLI or UI.



Section 4. Contributors

This document was adapted from the original by Joshua Darnell, and originally written by Joshua Darnell and Paul Stusiak.

Parts of this proposal are based on the RETS Validation Expression language as expressed in RETS 1.9 and RCP 61. Thanks to Libor Viktorin, Mark Sleeman, Sergio Del Rio, and Paul Stusiak for that work. Thanks to Rob Larson for his collaboration on the Rules Resource proposal and also to Bryan Burgers and Zenlist for providing additional feedback during implementation as well as compliance tests.



Section 5: References

Please see the following references for more information regarding topics covered in this document:



Section 6: Appendices

None at this time.



Section 7: License

This document is covered by the RESO EULA.

Please contact RESO if you have any questions.