Network Working Group                                         P. Cordell
Internet-Draft                                                 Codalogic
Intended status: Standards Track                               A. Newton
Expires: September 22, 2016                                         ARIN
                                                          March 21, 2016


                 Co-Constraints for JSON Content Rules
                  draft-cordell-jcr-co-constraints-00

Abstract

   JSON Content Rules (JCR) [JCR] provides a powerful, intuitive and
   concise method for defining the structure of JSON [RFC7159] messages.
   However, modern JSON usage patterns occasionally mean that JCR alone
   is not able to capture the required constraints in a satisfactory
   way.  This document describes JCR Co-Constraints (JCRCC) which
   defines additional JCR directives and annotations that can be added
   to a JCR ruleset in order to define more detailed constraints on JSON
   messages.

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at http://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on September 22, 2016.

Copyright Notice

   Copyright (c) 2016 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents
   (http://trustee.ietf.org/license-info) in effect on the date of
   publication of this document.  Please review these documents
   carefully, as they describe your rights and restrictions with respect



Cordell & Newton       Expires September 22, 2016               [Page 1]


Internet-Draft             JCR Co-Constraints                 March 2016


   to this document.  Code Components extracted from this document must
   include Simplified BSD License text as described in Section 4.e of
   the Trust Legal Provisions and are provided without warranty as
   described in the Simplified BSD License.

1.  Introduction

   JSON Content Rules [JCR] provides a powerful, intuitive and concise
   method for defining the structure of JSON [RFC7159] messages.  In
   addition to describing the overall structure of JSON messages, JCR
   aims to capture the constraints that are imposed on individual items
   within a message.  However, modern JSON usage occasionally requires
   constraints that can't be expressed by JCR alone.  JCR Co-Constraints
   (JCRCC) defines additional JCR directives and annotations that can be
   added to a JCR ruleset in order to define more detailed constraints
   on items within a JSON message, and also supports specifying
   constraints that depend on the relationship of multiple JSON items.

   JCRCC constraints represent an additional layer of validation on top
   of the validation provided by JCR alone.  JCRCC constraints may
   indicate that a JSON instance that was determined to be valid by the
   rules of a JCR ruleset is in fact invalid.  However, if the JCR
   ruleset indicates that the JSON instance is invalid, JCRCC
   constraints can not override that and declare the instance to be
   valid.  A JCR processor MAY ignore the JCRCC annotations and
   directives, perhaps only issuing a warning for encountering an
   unknown annotation or directive.

   JCRCC uses the annotations @{id}, @{when} and @{assert} along with
   the directive #{constraint}.  The @{id} annotation is used to
   identify an item in a JSON message that contributes to the assessment
   of a JSON instance's validity.  The other three each include a
   'condition' expression that yields a Boolean true or false result.
   The validity of the JSON instance is dependent on the results of the
   various condition expressions.  Condition expressions are made up of
   identifiers, comparators, combiners and functions.  Each of these
   aspects is described in more detail below.

2.  Definitions

   Assessment -
         The process whereby it is determined whether a JSON instance is
         valid according to a JCR ruleset (which may or may not include
         JCR co-constraints).

   JSON instance -
         A JSON message that is being validated against a JCR ruleset
         (which may augmented using JCRCC).



Cordell & Newton       Expires September 22, 2016               [Page 2]


Internet-Draft             JCR Co-Constraints                 March 2016


   JSON instance item -
         An object member or a value in a JSON instance.  Often JCRCC
         annotations will define an identifier that will be associated
         with a JSON instance item.

3.  Annotations and Directives

   JCRCC uses the annotations @{id}, @{when} and @{assert} plus the
   directive #{constraint}.

3.1.  The @{id} Annotation

   The @{id} annotation creates an identifier for a rule in a JCR
   ruleset.  A maximum of one @{id} annotation is permitted per rule.
   It has the form:

       @{id name}

   where 'name' corresponds to the 'name' production in the JCR ABNF.

   The @{id} annotation associates an identifier with the rule on which
   it is placed.  The identifier can then be used in condition
   expressions to reference the corresponding item in JSON instance
   items that are mapped to the JCR rule during validation.

   For example, a JCR rule of:

       "type" @{id t} : string

   might associate the identifier 't' with a JSON instance item such as:

       "type" : "shutdown"

3.2.  The @{when} Annotation

   The @{when} annotation has two similar roles.  If a JCR rule
   indicates that a JSON instance item is optional, then it can be used
   to describe the conditions when the item is present or absent.
   Similarly, if a JCR rule indicates that an item has a choice of
   types, then the @{when} annotation can be used to indicate which of
   the possible sub-rules is applicable in the current validation
   instance.  Only one @{when} annotation per rule is permitted.

   The @{when} annotation includes a single 'condition'.  In the case of
   using the @{when} annotation with an optional instance, if the
   condition yields a 'true' result, then the JSON instance item
   associated with the JCR rule MUST be present, otherwise it MUST be
   absent.



Cordell & Newton       Expires September 22, 2016               [Page 3]


Internet-Draft             JCR Co-Constraints                 March 2016


   When the @{when} annotation is used to select the applicable member/
   type rule within a group or type choice, the condition of each
   @{when} annotation is evaluated in turn (from left to right as shown
   in the JCR rule) and the member/type rule that corresponds to the
   first @{when} condition that yields a 'true' result is selected.  If
   none of the @{when} annotations on a group or type choice yields
   true, this indicates an invalid instance.  When a member/type rule
   within a group or type choice that has @{when} annotations on other
   members/types, but does not itself have an @{when} annotation, this
   indicates the default case.  In essence, if a rule contains @{when}
   annotations, then an absent @{when} annotation on a member/type rule
   is equivalent to @{when true}.

   As an example, a @{when} annotation on an optional item may look as
   follows:

       ? @{when $t == "shutdown"} "uptime" : integer

   This indicates that the "uptime" member should be present if the JSON
   instance item associated with a JCR rule with an @{id t} annotation
   has the value "shutdown".

   A @{when} annotation on a group may look as follows:

       details ( @{when $t == "boot"} boot-details |
                   @{when $t == "shutdown"} shutdown-details |
                   default-details )

   This indicates that the JCR rule named 'boot-details' is applicable
   when the JSON instance item associated with an @{id t} annotation has
   the value "boot", the rule 'shutdown-details' is applicable when the
   value of the $t item is "shutdown", otherwise the rule 'default-
   details' is applicable.  (The rules identified by 'boot-details',
   'shutdown-details' and 'default-details' might be groups that act as
   mixins for the rule in which the 'details' rule is used.)

   The @{when} annotation can reference identifiers in siblings,
   ancestors, and descendants.  To avoid circular or ambiguous
   dependencies, the identifiers in descendants must not be part of
   arrays or descendants of itself or descendants of siblings that have
   @{when} annotations.  The latter restriction avoids needing to know
   whether a secondary @{when} annotation yields 'true' in order to
   determine if the @{when} annotation being assessed yields 'true'.
   When seeking identifiers, siblings are inspected first, followed by
   the nearest ancestor, followed by the nearest descendent.  If it is
   desired to look for an identifier that is a descendent without first
   looking for an identifier that is an ancestor, then the




Cordell & Newton       Expires September 22, 2016               [Page 4]


Internet-Draft             JCR Co-Constraints                 March 2016


   'descendent()' method can be called on the name of the identifier.
   For example:

       ? @{when descendent($s) == "on"} "watts" : integer

3.3.  The @{assert} Annotation

   The @{assert} annotation is used to specify additional constraints on
   an item that can't be expressed using JCR alone.  The @{assert}
   annotation contains a single condition that must yield 'true' for the
   JSON instance item to be considered valid.  A maximum of one
   @{assert} annotations is permitted per rule.

   @{assert} annotations are evaluated after all sibling @{when}
   annotations have been evaluated, and constraints specified by the
   underlying JCR rule have been assessed.  An item may have both a
   @{when} annotation and a @{assert} annotation.  If the condition in
   the @{when} annotation yields 'false', then the item it corresponds
   to should be absent in the JSON instance, so the @{assert} condition
   is not evaluated.  If the JSON instance item is not valid according
   the underlying JCR rule, then validation fails at that point and the
   @{assert} annotation is not assessed.

   When seeking identifiers referenced in an @{assert} annotation,
   siblings are inspected first, followed by the nearest ancestor,
   followed by the nearest descendent.  If it is desired to look for an
   identifier that is a descendent without first looking for an
   identifier that is an ancestor, then the 'descendent()' method can be
   called on the name of the identifier.

   An example @{assert} annotation might be:

       "index" @{assert $ % 2 == 0} : integer ; Must be even

3.4.  The #{constraint} Directive

   The #{constraint} directive offers a way to express conditions
   external to @{when} and @{assert} annotations.  #{constraint}
   directives can be viewed as a macro substitution mechanism.  @{when}
   and @{assert} annotations, and other #{constraint} directives can
   reference conditions defined by a #{constraint}.  The format of a
   #{constraint} directive is as follows:

       #{constraint name condition}

   where 'name' corresponds to the 'name' production in the JCR ABNF,
   and the 'condition' is the same as used in @{when} and @{assert}
   annotations and is as described below.



Cordell & Newton       Expires September 22, 2016               [Page 5]


Internet-Draft             JCR Co-Constraints                 March 2016


   Conceptually at least, the 'condition' in a #{constraint} directive
   is substituted into @{when}, @{assert} annotations and other
   #{constraint} directives wherever the constraint's 'name' is
   referenced.  (In practice, for the purposes of efficiency, the result
   of a #{constraint} directive may be cached or memoized, to avoid
   repeated computation of the sub-condition.  However, such
   optimizations are beyond the scope of this document.)

   An example usage, equating to the earlier example, might be:

       #{constraint is_even $ % 2 == 0}
       "index" @{assert @is_even} : integer ; Must be even

4.  Conditions

   The @{when} annotation, @{assert} annotation and #{constraint}
   directive contain 'conditions'.  These are made up of 'identifiers',
   'comparators', 'combiners' and 'functions' as described below.

4.1.  Identifiers

   Identifiers are used to refer to items in the JCR, and #{constraint}
   directives.  They have a few different forms.

   '$' on its own refers to the member / type expressed by the current
   JCR rule.  For example:

       int-pairs @{assert count( $ ) % 2 == 0} [ : integer ]

   The form '$name' and '$alias.name' form is an item reference and
   refers to members and types identified by JCR rules by @{id}
   annotations.  An 'alias' is set up using the normal JCR #import
   directive and allows members / types outside the current ruleset to
   be identified.  For example:

       @{id type} : string, {
       ? "uptime" @{when $type == "shutdown"} : integer }

   An item reference that is not part of an 'operator' or a 'comparator'
   sub-expression yields 'true' if the referenced item is present in the
   JSON instance being validated, and 'false' if not.  For example, the
   following says that the 'dob' member must be present if the 'name'
   member is present:

         ? "name" @{id n} : string,
         ? "dob" @{when $n} : full-date





Cordell & Newton       Expires September 22, 2016               [Page 6]


Internet-Draft             JCR Co-Constraints                 March 2016


   An item reference that is part of an 'operator' or a 'comparator'
   sub-expression yields the value of the corresponding JSON instance
   item.

   Item references may also be used as arguments to functions.

   The '@name' and '@alias.name' form is a constraint reference and
   refers to a condition expressed in a #{constraint} directive.  An
   'alias' is set up using the normal JCR #import directive and allows
   constraints outside the current ruleset to be identified.  For
   example:

       #{constraint is_even $ % 2 == 0}
       "index" : @{assert @is_even} integer ; Must be even

4.2.  Operators

   The values of JSON instance items identified by identifiers, values
   yielded by other 'operators' and values returned by 'functions' can
   be subject to computations using 'operators'.  The supported
   operators are '+', '-', '*', '/' and '%'.  They have their usual
   C-family programming language meaning.  The precedence of the
   operators is as-per normal mathematics rules.  Operators have higher
   precedence than comparators.

4.3.  Comparators

   The values of JSON instance items identified by identifiers, values
   yielded by 'operators' and values returned by 'functions' can be
   compared using 'comparators'.  The comparators are the usual '<',
   '<=', '==', '!=', '>=' and '>', and have their usual C-family
   language meaning.  Comparators yield a 'true' or 'false' result.

   When an identifier referenced by a comparator is absent, then the
   comparison returns 'false'.  For example:

       $t == "boot"

   is equivalent to:

       ( $t && $t == "boot" )

   Similarly:

       $t == "boot" || $other == "close"

   is equivalent to:




Cordell & Newton       Expires September 22, 2016               [Page 7]


Internet-Draft             JCR Co-Constraints                 March 2016


       ( $t && $t == "boot" ) || ( $other && $other == "close" )

   And:

       length( $first ) > length( $second )

   is equivalent to:

       ( $first && $second && length( $first ) > length( $second ) )

   Comparators have higher precedence than combiners.

4.4.  Combiners

   Multiple results of 'comparators' or standalone identifiers can be
   combined using 'combiners'.  The supported combiners are '&&' and
   '||'.  They have their usual C-family programming language meaning.

4.5.  Functions

   JCRCC supports a number of functions that can be used to yield
   specific information about a JSON instance item referenced by an
   identifier.  Some functions can operate on multiple types of
   argument, such as identifiers or strings.  In the function
   descriptions below, arguments that can take multiple different types
   have each type listed, separated by the pipe symbol (|).  For
   example, an argument description of "identifier | string" indicates
   that the function can take an identifier or a string as an argument.

   The functions are as follows:

   name( identifier ) -
         Returns the member name of the JSON instance item associated
         with the identifier as a string.

   length( identifier | string ) -
         If the argument is an identifier, the value of the JSON
         instance item associated with it MUST be represented using a
         JSON string (i.e. it could be defined as a JCR ip4 type that is
         represented in JSON using the string format).  The function
         returns the length of the string in Unicode code points.  To
         return the length of a JSON instance item's member name, do
         "length( name( $t ) )".

   count( identifier ) -
         The JSON instance item associated with the identifier MUST be
         an array.  The function returns the number of items in the
         array.



Cordell & Newton       Expires September 22, 2016               [Page 8]


Internet-Draft             JCR Co-Constraints                 March 2016


   capture( identifier | string, regex ) -
         The regex in the capture function MUST include a capture
         expression (i.e. a suitable term in brackets).  The regex is
         applied to the input string, or the string value of the JSON
         instance item associated with the identifier, and the sub-
         string captured by the regex capture expression is returned.

   descendent( identifier ) -
         The normal order of identifier look up is, siblings, followed
         by ancestors, followed by descendents.  This function will
         cause the lookup to be in the order siblings followed by
         descendents.  It returns a reference to a JSON instance item
         that can be used in place of an identifier.  For example,
         "length( name( descendent( $t ) ) )".

   error( q_string ) -
         This function can be used for reporting error messages.  The
         text in the q_string may be subject to value interpolation and
         internationalization by an implementation, but this is not
         required.  It always returns false.  For example: @{assert
         $%2==0 || error("value must be even")} :integer

   is_null( identifier ), is_boolean( identifier ), is_string(
   identifier ), is_float( identifier ), is_integer( identifier ),
   is_ip4( identifier ), is_ip6( identifier ), is_fqdn( identifier ),
   is_idn( identifier ), is_uri( identifier ), is_phone( identifier ),
   is_email( identifier ), is_full-date( identifier ), is_full-time(
   identifier ), is_date-time( identifier ), is_base64( identifier ) -
         This set of functions return true if the JSON instance item
         associated with the identifier has the corresponding type, and
         false otherwise.

4.6.  If-Then-Else

5.  ABNF

   The ABNF is 'work in progress'.  It currently looks as below.  This
   does not capture where spaces are permitted.













Cordell & Newton       Expires September 22, 2016               [Page 9]


Internet-Draft             JCR Co-Constraints                 March 2016


   condition = relational ( * ( "&&" relational ) /
                            * ( "||" relational ) )

   relational = ["!"] value / value comparator value /
                ["!"] condition-group / ternary

   value = identifier / constant / function / "@" [ alias "." ] name

   identifier = "$" / "$" [ alias "." ] name

   constant = "null" / "true" / "false" / integer / float /
              q_string / regex

   comparator = "==" / "!=" / "<" / "<=" / ">=" / ">"

   condition-group = "(" condition ")"

   ternary = "if" "(" condition ")" "then" "(" condition ")"
             "else" "(" condition ")"

   function = "name" "(" identifier ")" /
              "length" "(" identifier ")" /
              "count" "(" identifier ")" /
              "capture" "(" regex "," identifier ")" /
              "descendent" "(" identifier ")" /
              "error" "(" q_string ")" /
              "is_integer" "(" identifier ")" /
              "is_float" "(" identifier ")" /
              etc...

6.  References

6.1.  Normative References

   [JCR]      Newton, A. and P. Cordell, "A Language for Rules
              Describing JSON Content", October 2015,
              <https://www.ietf.org/id/draft-newton-json-content-rules-
              05.txt>.

   [RFC7159]  Bray, T., Ed., "The JavaScript Object Notation (JSON) Data
              Interchange Format", RFC 7159, DOI 10.17487/RFC7159, March
              2014, <http://www.rfc-editor.org/info/rfc7159>.

6.2.  Infomative References







Cordell & Newton       Expires September 22, 2016              [Page 10]


Internet-Draft             JCR Co-Constraints                 March 2016


   [ARIN_JCR_VALIDATOR]
              American Registry for Internet Numbers, "JSON Content
              Rules Validator (Work In Progress)",
              <https://github.com/arineng/jcrvalidator>.

   [CODALOGIC_JCR_VALIDATOR]
              Codalogic, "cl-jcr-parser (Work In Progress)",
              <https://github.com/codalogic/cl-jcr-parser>.

Appendix A.  JCR Implementations

   The following implementations, [ARIN_JCR_VALIDATOR] and
   [CODALOGIC_JCR_VALIDATOR] have influenced the development of this
   document.

Authors' Addresses

   Pete Cordell
   Codalogic
   PO Box 30
   Ipswitch  IP5 2WY
   UK

   Email: pete.cordell@codalogic.com
   URI:   http://www.codalogic.com


   Andrew Lee Newton
   American Registry for Internet Numbers
   3635 Concorde Parkway
   Chantilly, VA  20151
   US

   Email: andy@arin.net
   URI:   http://www.arin.net
















Cordell & Newton       Expires September 22, 2016              [Page 11]