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 |
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.
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.
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.
This specification consists of the following:
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.
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. |
For detailed information, please see the Validation Expressions grammar.
This section contains examples to help illustrate how Validatine Expressions can be used.
3 + 5
1 * 3 + 2 - 5
To get current value of any field, use the Data Dictionary name: ListPrice
Supported for backwards compatibility with RETS:
[ListPrice]
ListPrice > 0
LAST Status != 'Sold'
Returns true if ListPrice has changed.
ListPrice != LAST ListPrice
foo()
foo('bar', 'baz', 42)
Functions MUST NOT use any FIELD_NAMEs or reserved words.
(ListPrice, Status, 3+5, LAST Status, (1, 2, 3))
ListPrice > 5.01 .AND. (1, 2, 3) .CONTAINS. 3 .OR. (Status .IN. ('Active', 'Pending') .AND. .MEMBER_MLS_SECURITY_CLASS. != 'Admin')
ListPrice > 5.01 .AND. (1, 2, 3) .CONTAINS. 3 .OR. Status .IN. ('Active', 'Pending') .AND. .MEMBER_MLS_SECURITY_CLASS. != 'Admin'
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 |
This proposal also adds support for the following collection operators:
DIFFERENCE()
INTERSECTION()
UNION()
Which are intended to produce types in the following manner:
LIST()
or SET()
should
return LIST()
or SET()
, respectively.
UNION(LIST('a', 'b', 3+5), LIST(6))
should return LIST('a', 'b', 6, 8)
LIST()
or SET()
should return LIST()
DIFFERENCE(LIST(1, 2, 3), SET(3))
should return LIST(1, 2)
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 |
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:
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 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.
Sometimes it might be necessary to communicate that a given rule has changed.
The Rules Resource providers the Rule Version for these scenarios.
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"
}]
}
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.
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.
Please see the following references for more information regarding topics covered in this document:
None at this time.
This document is covered by the RESO EULA.
Please contact RESO if you have any questions.