idnits 2.17.1 draft-ucarion-jddf-00.txt: Checking boilerplate required by RFC 5378 and the IETF Trust (see https://trustee.ietf.org/license-info): ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/1id-guidelines.txt: ---------------------------------------------------------------------------- No issues found here. Checking nits according to https://www.ietf.org/id-info/checklist : ---------------------------------------------------------------------------- No issues found here. Miscellaneous warnings: ---------------------------------------------------------------------------- == The copyright year in the IETF Trust and authors Copyright Line does not match the current year -- The document date (August 22, 2019) is 1702 days in the past. Is this intentional? Checking references for intended status: Informational ---------------------------------------------------------------------------- -- Looks like a reference, but probably isn't: '1' on line 805 -- Looks like a reference, but probably isn't: '2' on line 805 -- Looks like a reference, but probably isn't: '3' on line 805 == Outdated reference: A later version (-02) exists of draft-handrews-json-schema-01 Summary: 0 errors (**), 0 flaws (~~), 2 warnings (==), 4 comments (--). Run idnits with the --verbose option for more detailed information about the items above. -------------------------------------------------------------------------------- 2 Independent Submission U. Carion 3 Internet-Draft August 22, 2019 4 Intended status: Informational 5 Expires: February 23, 2020 7 JSON Data Definition Format (JDDF) 8 draft-ucarion-jddf-00 10 Abstract 12 JSON Data Definition Format (JDDF) is a portable method for 13 describing the format of JavaScript Object Notation (JSON) data and 14 the errors associated with ill-formed data. JDDF is designed to 15 enable code generation from schemas. 17 Status of This Memo 19 This Internet-Draft is submitted in full conformance with the 20 provisions of BCP 78 and BCP 79. 22 Internet-Drafts are working documents of the Internet Engineering 23 Task Force (IETF). Note that other groups may also distribute 24 working documents as Internet-Drafts. The list of current Internet- 25 Drafts is at https://datatracker.ietf.org/drafts/current/. 27 Internet-Drafts are draft documents valid for a maximum of six months 28 and may be updated, replaced, or obsoleted by other documents at any 29 time. It is inappropriate to use Internet-Drafts as reference 30 material or to cite them other than as "work in progress." 32 This Internet-Draft will expire on February 23, 2020. 34 Copyright Notice 36 Copyright (c) 2019 IETF Trust and the persons identified as the 37 document authors. All rights reserved. 39 This document is subject to BCP 78 and the IETF Trust's Legal 40 Provisions Relating to IETF Documents 41 (https://trustee.ietf.org/license-info) in effect on the date of 42 publication of this document. Please review these documents 43 carefully, as they describe your rights and restrictions with respect 44 to this document. Code Components extracted from this document must 45 include Simplified BSD License text as described in Section 4.e of 46 the Trust Legal Provisions and are provided without warranty as 47 described in the Simplified BSD License. 49 Table of Contents 51 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 52 1.1. Terminology . . . . . . . . . . . . . . . . . . . . . . . 4 53 2. Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 54 2.1. Extending JDDF's syntax . . . . . . . . . . . . . . . . . 11 55 3. Semantics . . . . . . . . . . . . . . . . . . . . . . . . . . 12 56 3.1. Allowing additional properties . . . . . . . . . . . . . 12 57 3.2. Errors . . . . . . . . . . . . . . . . . . . . . . . . . 13 58 3.3. Forms . . . . . . . . . . . . . . . . . . . . . . . . . . 13 59 3.3.1. Empty . . . . . . . . . . . . . . . . . . . . . . . . 14 60 3.3.2. Ref . . . . . . . . . . . . . . . . . . . . . . . . . 14 61 3.3.3. Type . . . . . . . . . . . . . . . . . . . . . . . . 15 62 3.3.4. Enum . . . . . . . . . . . . . . . . . . . . . . . . 18 63 3.3.5. Elements . . . . . . . . . . . . . . . . . . . . . . 18 64 3.3.6. Properties . . . . . . . . . . . . . . . . . . . . . 19 65 3.3.7. Values . . . . . . . . . . . . . . . . . . . . . . . 22 66 3.3.8. Discriminator . . . . . . . . . . . . . . . . . . . . 23 67 4. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 26 68 5. Security Considerations . . . . . . . . . . . . . . . . . . . 27 69 6. References . . . . . . . . . . . . . . . . . . . . . . . . . 27 70 6.1. Normative References . . . . . . . . . . . . . . . . . . 27 71 6.2. Informative References . . . . . . . . . . . . . . . . . 28 72 Appendix A. Comparison with CDDL . . . . . . . . . . . . . . . . 28 73 Appendix B. Examples . . . . . . . . . . . . . . . . . . . . . . 30 74 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 31 75 Author's Address . . . . . . . . . . . . . . . . . . . . . . . . 31 77 1. Introduction 79 This document describes a schema language for JSON [RFC8259] called 80 JSON Data Definition Format (JDDF). The name JDDF is chosen to avoid 81 confusion with "JSON Schema" from [I-D.handrews-json-schema]. 83 There exist many options for describing JSON data. JDDF's niche is 84 to focus on enabling code generation from schemas; to this end, 85 JDDF's expressiveness is intentionally limited to be no more powerful 86 than what can be expressed in the type systems of mainstream 87 languages. 89 The goals of JDDF are to: 91 o Provide an unambiguous description of the overall structure of a 92 JSON document. 94 o Be able to describe common JSON datatypes and structures. 96 o Provide a single format that is readable and editable by both 97 humans and machines, and which can be embedded within other JSON 98 documents. 100 o Enable code generation from JDDF schemas. 102 o Provide a standardized format for errors when data does not 103 conform with a schema. 105 JDDF is intentionally designed as a rather minimal schema language. 106 For example, JDDF is homoiconic (it both describes, and is written 107 in, JSON) yet is incapable of describing in detail its own structure. 108 By keeping the expressiveness of the schema language minimal, JDDF 109 makes code generation and standardized errors easier to implement. 111 JDDF's feature set is designed to represent common patterns in JSON- 112 using applications, while still having a clear correspondence to 113 programming languages in widespread use. Thus, JDDF supports: 115 o Signed and unsigned 8, 16, and 32-bit integers. A tool which 116 converts JDDF schemas into code can use "int8_t", "uint8_t", 117 "int16_t", etc., or their equivalents in the target language, to 118 represent these JDDF types. 120 o A distinction between "float32" and "float64". Code generators 121 can use "float" and "double", or their equivalents, for these JDDF 122 types. 124 o A "properties" form of JSON objects, corresponding to some sort of 125 struct. 127 o A "values" form of JSON objects, corresponding to some sort of 128 dictionary or associative array. 130 o A "discriminator" form of JSON objects, corresponding to a 131 discriminated (or "tagged") union. 133 The principle of common patterns in JSON is why JDDF does not support 134 64-bit integers, as these are usually transmitted over JSON in a non- 135 interoperable (i.e., ignoring the recommendations in Section 2.2 of 136 [RFC7493]) or mutually inconsistent (e.g., using hexadecimal versus 137 base64) ways. 139 The principle of clear correspondence to common programming languages 140 is why JDDF does not support, for example, a data type for numbers up 141 to 2**53-1. 143 It is expected that for many use-cases, a schema language of JDDF's 144 expressiveness is sufficient. Where a more expressive language is 145 required, alternatives exist in CDDL ([RFC8610], Concise Data 146 Definition Language) and others. 148 This document has the following structure: 150 The syntax of JDDF is defined in Section 2. Section 3 describes the 151 semantics of JDDF; this includes determining whether some data 152 satisfies a schema and what errors should be produced when the data 153 is unsatisfactory. Appendix A presents various JDDF schemas and 154 their CDDL equivalents. 156 1.1. Terminology 158 The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 159 "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and 160 "OPTIONAL" in this document are to be interpreted as described in 161 BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all 162 capitals, as shown here. These words may also appear in this 163 document in lower case as plain English words, absent their normative 164 meanings. 166 The term "JSON Pointer", when it appears in this document, is to be 167 understood as it is defined in [RFC6901]. 169 The terms "object", "member", "array", "number", "name", and "string" 170 in this document are to be interpreted as described in [RFC8259]. 172 The term "instance", when it appears in this document, refers to a 173 JSON value being validated against a JDDF schema. 175 2. Syntax 177 This section describes when a JSON document is a correct JDDF schema. 179 JDDF schemas may recursively contain other schemas. In this 180 document, a "root schema" is one which is not contained within 181 another schema, i.e. it is "top level". 183 A correct JDDF schema MUST match the "schema" CDDL rule described in 184 this section. A JDDF schema is a JSON object taking on an 185 appropriate form. It may optionally contain definitions (a mapping 186 from names to schemas) and additional data. 188 schema = { 189 form, 190 ? definitions: { * tstr => schema }, 191 ? additionalProperties: bool, 192 * non-keyword => * 193 } 195 ; This definition prohibits non-keyword from matching any of the 196 ; keywords defined later. 197 non-keyword = 198 (((((((((tstr .ne "definitions") 199 .ne "additionalProperties") 200 .ne "ref") 201 .ne "type") 202 .ne "enum") 203 .ne "elements") 204 .ne "properties") 205 .ne "optionalProperties") 206 .ne "values") 207 .ne "discriminator" 209 Figure 1: CDDL Definition of a Schema 211 This is not a correct JDDF schema, as its "definitions" object 212 contains a number, which is not a schema: 214 { "definitions": { "foo": 3 }} 216 Here is an example of a valid schema using the "properties", "type", 217 and "ref" forms, which will be described later in this section: 219 { 220 "strict": false, 221 "definitions": { 222 "user": { 223 "properties": { 224 "name": { "type": "string" }, 225 "create_time": { "type": "timestamp" } 226 } 227 } 228 }, 229 "elements": { 230 "ref": "user" 231 } 232 } 233 JDDF schemas can take on one of eight forms. These forms are defined 234 so as to be mutually exclusive; a schema cannot satisfy multiple 235 forms at once. 237 form = empty / 238 ref / 239 type / 240 enum / 241 elements / 242 properties / 243 values / 244 discriminator 246 Figure 2: CDDL Definition of the Schema Forms 248 The first form, "empty", is trivial. It is meant for matching any 249 instance: 251 empty = {} 253 Figure 3: CDDL Definition of the Empty Form 255 Thus, this is a correct schema: 257 {} 259 The second form, "ref", is for when a schema is meant to be defined 260 in terms of something in "definitions": 262 ref = { ref: tstr } 264 Figure 4: CDDL Definition of the Ref Form 266 For a schema to be correct, the "ref" value must refer to one of the 267 definitions found at the root level of the schema it appears in. 268 More formally, for a schema _S_ of the "ref" form: 270 o Let _B_ be the root schema containing the schema, or the schema 271 itself if it is a root schema. 273 o Let _R_ be the value of the member of _S_ with the name "ref". 275 If the schema is correct, then _B_ must have a member _D_ with the 276 name "definitions", and _D_ must contain a member whose name equals 277 _R_. 279 Here is a correct example of "ref" being used to avoid re-defining 280 the same thing twice: 282 { 283 "definitions": { 284 "coordinates": { 285 "properties": { 286 "lat": { "type": "float32" }, 287 "lng": { "type": "float32" } 288 } 289 } 290 }, 291 "properties": { 292 "user_location": { "ref": "coordinates" }, 293 "server_location": { "ref": "coordinates" } 294 } 295 } 297 However, this schema is incorrect, as it refers to a definition that 298 doesn't exist: 300 { 301 "definitions": { "foo": { "type": "float32" }}, 302 "ref": "bar" 303 } 305 This schema is incorrect as well, as it refers to a definition that 306 doesn't exist at the root level. The non-root definition is 307 immaterial: 309 { 310 "definitions": { "foo": { "type": "float32" }}, 311 "elements": { 312 "definitions": { "bar": { "type": "float32" }}, 313 "ref": "bar" 314 } 315 } 317 The third form, "type", constrains instances to have a particular 318 primitive type. The precise meaning of each of the primitive types 319 is described in Section 3. 321 type = { type: "boolean" / num-type / "string" / "timestamp" } 322 num-type = "float32" / "float64" / 323 "int8" / "uint8" / "int16" / "uint16" / "int32" / "uint32" 325 Figure 5: CDDL Definition of the Type Form 327 For example, this schema constrains instances to be strings that are 328 correct [RFC3339] timestamps: 330 { "type": "timestamp" } 332 The fourth form, "enum", describes instances whose value must be one 333 of a finite, predetermined set of values: 335 enum = { enum: [+ tstr] } 337 Figure 6: CDDL Definition of the Enum Form 339 The values within "[+ tstr]" MUST NOT contain duplicates. Thus, the 340 following is a correct schema: 342 { "enum": ["IN_PROGRESS", "DONE", "CANCELED"] } 344 But this is not a correct schema, as "B" is duplicated: 346 { "enum": ["A", "B", "B"] } 348 The fifth form, "elements", describes instances that must be arrays. 349 A further sub-schema describes the elements of the array. 351 elements = { elements: schema } 353 Figure 7: CDDL Definition of the Elements Form 355 Here is a schema describing an array of [RFC3339] timestamps: 357 { "elements": { "type": "timestamp" }} 359 The sixth form, "properties", describes JSON objects being used as a 360 "struct". A schema of this form specifies the names of required and 361 optional properties, as well as the schemas each of those properties 362 must satisfy: 364 ; One of properties or optionalProperties may be omitted, 365 ; but not both. 366 properties = with-properties / with-optional-properties 368 with-properties = { 369 properties: * tstr => schema, 370 ? optionalProperties * tstr => schema 371 } 373 with-optional-properties = { 374 ? properties: * tstr => schema, 375 optionalProperties: * tstr => schema 376 } 378 Figure 8: CDDL Definition of the Properties Form 380 If a schema has both a member named "properties" (with value _P_) and 381 another member named "optionalProperties" (with value _O_), then _O_ 382 and _P_ MUST NOT have any member names in common. This is to prevent 383 ambiguity as to whether a property is optional or required. 385 Thus, this is not a correct schema, as "confusing" appears in both 386 "properties" and "optionalProperties": 388 { 389 "properties": { "confusing": {} }, 390 "optionalProperties": { "confusing": {} } 391 } 393 Here is a correct schema, describing a paginated list of users: 395 { 396 "properties": { 397 "users": { 398 "elements": { 399 "properties": { 400 "id": { "type": "string" }, 401 "name": { "type": "string" }, 402 "create_time": { "type": "timestamp" } 403 }, 404 "optionalProperties": { 405 "delete_time": { "type": "timestamp" } 406 } 407 } 408 }, 409 "next_page_token": { "type": "string" } 410 } 411 } 412 The seventh form, "values", describes JSON objects being used as an 413 associative array. A schema of this form specifies the form all 414 member values must satisfy, but places no constraints on the member 415 names: 417 values = { values: * tstr => schema } 419 Figure 9: CDDL Definition of the Values Form 421 Thus, this is a correct schema, describing a mapping from strings to 422 numbers: 424 { "values": { "type": "float32" }} 426 Finally, the eighth form, "discriminator", describes JSON objects 427 being used as a discriminated union. A schema of this form specifies 428 the "tag" (or "discriminator") of the union, as well as a mapping 429 from tag values to the appropriate schema to use. 431 ; Note well: the values of mapping are of the properties form. 432 discriminator = { tag: tstr, mapping: * tstr => properties } 434 Figure 10: CDDL Definition of the Discriminator Form 436 To prevent ambiguous or unsatisfiable contstraints on the "tag" of a 437 discriminator, an additional constraint on schemas of the 438 discriminator form exists. For schemas of the discriminator form: 440 o Let _D_ be the schema member with the name "discriminator". 442 o Let _T_ be the member of _D_ with the name "tag". 444 o Let _M_ be the member of _D_ with the name "mapping". 446 If the schema is correct, then all member values _S_ of _M_ will be 447 schemas of the "properties" form. For each member _P_ of _S_ whose 448 name equals "properties" or "optionalProperties", _P_'s value, which 449 must be an object, MUST NOT contain any members whose name equals 450 _T_'s value. 452 Thus, this is an incorrect schema, as "event_type" is both the value 453 of "tag" and a member name in one of the "mapping" member 454 "properties": 456 { 457 "tag": "event_type", 458 "mapping": { 459 "is_event_type_a_string_or_a_float32?": { 460 "properties": { "event_type": { "type": "float32" }} 461 } 462 } 463 } 465 However, this is a correct schema, describing a pattern of data 466 common in JSON-based messaging systems: 468 { 469 "tag": "event_type", 470 "mapping": { 471 "account_deleted": { 472 "properties": { 473 "account_id": { "type": "string" } 474 } 475 }, 476 "account_payment_plan_changed": { 477 "properties": { 478 "account_id": { "type": "string" }, 479 "payment_plan": { "enum": ["FREE", "PAID"] } 480 }, 481 "optionalProperties": { 482 "upgraded_by": { "type": "string" } 483 } 484 } 485 } 486 } 488 2.1. Extending JDDF's syntax 490 This document does not describe any extension mechanisms for JDDF 491 schema validation, which is described in Section 3. However, schemas 492 (through the "non-keyword" CDDL rule in {{syntax}) are defined to 493 allow members whose names are not equal to any of the specially- 494 defined keywords (i.e. "definitions", "elements", etc.). Call these 495 members "non-keyword members". 497 Users MAY add additional, non-keyword members to JDDF schemas to 498 convey information that is not pertinent to validation. For example, 499 such non-keyword members could provide hints to code generators, or 500 trigger some special behavior for a library that generates user 501 interfaces from schemas. 503 Users SHOULD NOT expect non-keyword members to be understood by other 504 parties. As a result, if consistent validation with other parties is 505 a requirement, users SHOULD NOT use non-keyword members to affect how 506 schema validation, as described in Section 3, works. 508 3. Semantics 510 This section describes when an instance is valid against a correct 511 JDDF schema, and the standardized errors to produce when an instance 512 is invalid. 514 3.1. Allowing additional properties 516 Users will have different desired behavior with respect to 517 "unspcecified" members in an instance. For example: 519 { "properties": { "a": { "type": "string" }}} 521 Some users may expect that {"a": "foo", "b": "bar"} satisfies the 522 above schema. Others may disagree, as "b" is not one of the 523 properties described in the schema. In this document, allowing such 524 "unspecified" members happens when evaluation is in "allow additional 525 properties" mode. 527 Evaluation of a schema does not allow additional properties by 528 default, but can be overridden by setting "additionalProperties: 529 true" on the schema. 531 More formally, evaluation of a schema _S_ is in "allow additional 532 properties" mode if there exists a member of _S_ whose name equals 533 "additionalProperties", and whose value is a boolean "true". 534 Otherwise, evaluation of _S_ is not in "allow additional properties" 535 mode. 537 See Section 3.3.6 for how allowing unknown properties affects schema 538 evaluation, but briefly, the following schema: 540 { "properties": { "a": { "type": "string" }}} 542 Rejects {"a": "foo", "b": "bar"}, but the schema: 544 { 545 "additionalProperties": true, 546 "properties": { "a": { "type": "string" }} 547 } 549 Accepts {"a": "foo", "b": "bar"}. 551 Note that "additionalProperties" does not get "inherited" by sub- 552 schemas. For example, this schema: 554 { 555 "additionalProperties": true, 556 "elements": { 557 "properties": { 558 "a": { "type": "string" } 559 } 560 } 561 } 563 Rejects [{"a": "foo", "b": "bar"}]. The "additionalProperties" at 564 the root level does not affect the behavior of the sub-schema within 565 "elements". 567 3.2. Errors 569 To facilitate consistent validation error handling, this document 570 specifies a standard error format. Implementations SHOULD support 571 producing errors in this standard form. 573 The standard error format is a JSON array. The order of the elements 574 of this array is not specified. The elements of this array are JSON 575 objects with two members: 577 o A member with the name "instancePath", whose value is a JSON 578 string encoding a JSON Pointer. This JSON Pointer will point to 579 the part of the instance that was rejected. 581 o A member with the name "schemaPath", whose value is a JSON string 582 encoding a JSON Pointer. This JSON Pointer will point to the part 583 of the schema that rejected the instance. 585 The values for "instancePath" and "schemaPath" depend on the form of 586 the schema, and are described in detail in Section 3.3. 588 3.3. Forms 590 This section describes, for each of the eight JDDF schema forms, the 591 rules dictating whether an instance is accepted, as well as the 592 standardized errors to produce when an instance is invalid. 594 The forms a correct schema may take on are formally described in 595 Section 2. 597 3.3.1. Empty 599 The empty form is meant to describe instances whose values are 600 unknown, unpredictable, or otherwise unconstrained by the schema. 602 If a schema is of the empty form, then it accepts all instances. A 603 schema of the empty form will never produce any errors. 605 3.3.2. Ref 607 The ref form is for when a schema is meant to be defined in terms of 608 something in the "definitions" of the root schema. The ref form 609 enables schemas to be less repetitive, and also enables describing 610 recursive structures. 612 If a schema is of the ref form, then: 614 o Let _B_ be the root schema containing the schema, or the schema 615 itself if it is a root schema. 617 o Let _D_ be the member of _B_ with the name "definitions". By 618 Section 2, _D_ exists. 620 o Let _R_ be the value of the schema member with the name "ref". 622 o Let _S_ be the value of the member of _D_ whose name equals _R_. 623 By Section 2, _S_ exists, and is a schema. 625 The schema accepts the instance if and only if _S_ accepts the 626 instance. Otherwise, the standard errors to return in this case are 627 the union of the errors from evaluating _S_ against the instance. 629 For example, the schema: 631 { 632 "definitions": { "a": { "type": "float32" }}, 633 "ref": "a" 634 } 636 Accepts 123 but not false. The standard errors to produce when 637 evaluting false against this schema are: 639 [{ "instancePath": "", "schemaPath": "/definitions/a/type" }] 641 Note that the ref form is defined to only look up definitions at the 642 root level. Thus, with the schema: 644 { 645 "definitions": { "a": { "type": "float32" }}, 646 "elements": { 647 "definitions": { "a": { "type": "boolean" }}, 648 "ref": "foo" 649 } 650 } 652 The instance 123 is accepted, and false is rejected. The standard 653 errors to produce when evaluating false against this schema are: 655 [{ "instancePath": "", "schemaPath": "/definitions/a/type" }] 657 Though non-root definitions are not syntactically disallowed in 658 correct schemas, they are entirely immaterial to evaluating 659 references. 661 3.3.3. Type 663 The type form is meant to describe instances whose value is a 664 boolean, number, string, or timestamp ([RFC3339]). 666 If a schema is of the type form, then let _T_ be the value of the 667 member with the name "type". The following table describes whether 668 the instance is accepted, as a function of _T_'s value: 670 +-------------------+----------------------------------------------+ 671 | If _T_ equals ... | then the instance is accepted if it is ... | 672 +-------------------+----------------------------------------------+ 673 | boolean | equal to "true" or "false" | 674 | | | 675 | float32 | a JSON number | 676 | | | 677 | float64 | a JSON number | 678 | | | 679 | int8 | See Table 2 | 680 | | | 681 | uint8 | See Table 2 | 682 | | | 683 | int16 | See Table 2 | 684 | | | 685 | uint16 | See Table 2 | 686 | | | 687 | int32 | See Table 2 | 688 | | | 689 | uint32 | See Table 2 | 690 | | | 691 | string | a JSON string | 692 | | | 693 | timestamp | a JSON string encoding a [RFC3339] timestamp | 694 +-------------------+----------------------------------------------+ 696 Table 1: Accepted Values for Type 698 "float32" and "float64" are distinguished from each other in their 699 intent. "float32" indicates data intended to be processed as an IEEE 700 754 single-precision float, whereas "float64" indicates data intended 701 to be processed as an IEEE 754 double-precision float. Tools which 702 generate code from JDDF schemas will likely produce different code 703 for "float32" than for "float64". 705 If _T_ starts with "int" or "uint", then the instance is accepted if 706 and only if it is a JSON number encoding a value with zero fractional 707 part. Depending on the value of _T_, this encoded number must 708 additionally fall within a particular range: 710 +--------+---------------------------+---------------------------+ 711 | _T_ | Minimum Value (Inclusive) | Maximum Value (Inclusive) | 712 +--------+---------------------------+---------------------------+ 713 | int8 | -128 | 127 | 714 | | | | 715 | uint8 | 0 | 255 | 716 | | | | 717 | int16 | -32,768 | 32,767 | 718 | | | | 719 | uint16 | 0 | 65,535 | 720 | | | | 721 | int32 | -2,147,483,648 | 2,147,483,647 | 722 | | | | 723 | uint32 | 0 | 4,294,967,295 | 724 +--------+---------------------------+---------------------------+ 726 Table 2: Ranges for Integer Types 728 Note that 10, 10.0, and 1.0e1 encode values with zero fractional 729 part. 10.5 encodes a number with a non-zero fractional part. Thus 730 {"type": "int8"} accepts 10, 10.0, and 1.0e1, but not 10.5. 732 If the instance is not accepted, then the standard error for this 733 case shall have an "instancePath" pointing to the instance, and a 734 "schemaPath" pointing to the schema member with the name "type". 736 For example: 738 o The schema {"type": "boolean"} accepts false, but rejects 127. 740 o The schema {"type": "float32"} accepts 10.5, 127 and 128, but 741 rejects false. 743 o The schema {"type": "int8"} accepts 127, but rejects 10.5, 128 and 744 false. 746 o The schema {"type": "string"} accepts "1985-04-12T23:20:50.52Z" 747 and "foo", but rejects 127. 749 o The schema {"type": "timestamp"} accepts 750 "1985-04-12T23:20:50.52Z", but rejects "foo" and 127. 752 In all of the rejected examples just given, the standard error to 753 produce is: 755 [{ "instancePath": "", "schemaPath": "/type" }] 757 3.3.4. Enum 759 The enum form is meant to describe instances whose value must be one 760 of a finite, predetermined set of string values. 762 If a schema is of the enum form, then let _E_ be the value of the 763 schema member with the name "enum". The instance is accepted if and 764 only if it is equal to one of the elements of _E_. 766 If the instance is not accepted, then the standard error for this 767 case shall have an "instancePath" pointing to the instance, and a 768 "schemaPath" pointing to the schema member with the name "enum". 770 For example, the schema: 772 { "enum": ["PENDING", "DONE", "CANCELED"] } 774 Accepts "PENDING", "DONE", and "CANCELED", but it rejects both 123 775 and "UNKNOWN" with the standard errors: 777 [{ "instancePath": "", "schemaPath": "/enum" }] 779 3.3.5. Elements 781 The elements form is meant to describe instances that must be arrays. 782 A further sub-schema describes the elements of the array. 784 If a schema is of the elements form, then let _S_ be the value of the 785 schema member with the name "elements". The instance is accepted if 786 and only if all of the following are true: 788 o The instance is an array. Otherwise, the standard error for this 789 case shall have an "instancePath" pointing to the instance, and a 790 "schemaPath" pointing to the schema member with the name 791 "elements". 793 o If the instance is an array, then every element of the instance 794 must be accepted by _S_. Otherwise, the standard errors for this 795 case are the union of all the errors arising from evaluating _S_ 796 against elements of the instance. 798 For example, if we have the schema: 800 { 801 "elements": { 802 "type": "float32" 803 } 804 } 805 Then the instances [] and [1, 2, 3] are accepted. If instead we 806 evaluate false against that schema, the standard errors are: 808 [{ "instancePath": "", "schemaPath": "/elements" }] 810 Finally, if we evaluate the instance: 812 [1, 2, "foo", 3, "bar"] 814 The standard errors are: 816 [ 817 { "instancePath": "/2", "schemaPath": "/elements/type" }, 818 { "instancePath": "/4", "schemaPath": "/elements/type" } 819 ] 821 3.3.6. Properties 823 The properties form is meant to describe JSON objects being used as a 824 "struct". 826 If a schema is of the properties form, then the instance is accepted 827 if and only if all of the following are true: 829 o The instance is an object. 831 Otherwise, the standard error for this case shall have an 832 "instancePath" pointing to the instance, and a "schemaPath" 833 pointing to the schema member with the name "properties" if such a 834 schema member exists; if such a member doesn't exist, "schemaPath" 835 shall point to the schema member with the name 836 "optionalProperties". 838 o If the instance is an object and the schema has a member named 839 "properties", then let _P_ be the value of the schema member named 840 "properties". _P_, by Section 2, must be an object. For every 841 member name in _P_, a member of the same name in the instance must 842 exist. 844 Otherwise, the standard error for this case shall have an 845 "instancePath" pointing to the instance, and a "schemaPath" 846 pointing to the member of _P_ failing the requirement just 847 described. 849 o If the instance is an object, then let _P_ be the value of the 850 schema member named "properties" (if it exists), and _O_ be the 851 value of the schema member named "optionalProperties" (if it 852 exists). 854 For every member _I_ of the instance, find a member with the same 855 name as _I_'s in _P_ or _O_. By Section 2, it is not possible for 856 both _P_ and _O_ to have such a member. If the "discriminator tag 857 exemption" is in effect on _I_ (see Section 3.3.8), then ignore 858 _I_. Otherwise: 860 * If no such member in _P_ or _O_ exists and validation is not in 861 "allow additional properties" mode (see Section 3.1), then the 862 instance is rejected. 864 The standard error for this case has an "instancePath" pointing 865 to _I_, and a "schemaPath" pointing to the schema. 867 * If such a member in _P_ or _O_ does exist, then call this 868 member _S_. If _S_ rejects _I_'s value, then the instance is 869 rejected. 871 The standard error for this case is the union of the errors 872 from evaluating _S_ against _I_'s value. 874 An instance may have multiple errors arising from the second and 875 third bullet in the above. In this case, the standard errors are the 876 union of the errors. 878 For example, if we have the schema: 880 { 881 "properties": { 882 "a": { "type": "string" }, 883 "b": { "type": "string" } 884 }, 885 "optionalProperties": { 886 "c": { "type": "string" }, 887 "d": { "type": "string" } 888 } 889 } 891 Then each of the following instances (one on each line) are accepted: 893 { "a": "foo", "b": "bar" } 894 { "a": "foo", "b": "bar", "c": "baz" } 895 { "a": "foo", "b": "bar", "c": "baz", "d": "quux" } 896 { "a": "foo", "b": "bar", "d": "quux" } 898 If we evaluate the instance 123 against this schema, then the 899 standard errors are: 901 [{ "instancePath": "", "schemaPath": "/properties" }] 902 If instead we evalute the instance: 904 { "b": 3, "c": 3, "e": 3 } 906 The standard errors are: 908 [ 909 { "instancePath": "", 910 "schemaPath": "/properties/a" }, 911 { "instancePath": "/b", 912 "schemaPath": "/properties/b/type" }, 913 { "instancePath": "/c", 914 "schemaPath": "/optionalProperties/c/type" }, 915 { "instancePath": "/e", 916 "schemaPath": "" } 917 ] 919 If instead the schema had "additionalProperties: true", but was 920 otherwise the same: 922 { 923 "properties": { 924 "a": { "type": "string" }, 925 "b": { "type": "string" } 926 }, 927 "optionalProperties": { 928 "c": { "type": "string" }, 929 "d": { "type": "string" } 930 }, 931 "additionalProperties": true 932 } 934 And the instance remained the same: 936 { "b": 3, "c": 3, "e": 3 } 938 Then the errors from evaluating the instance against that 939 "additionalProperties: true" schema would be: 941 [ 942 { "instancePath": "", 943 "schemaPath": "/properties/a" }, 944 { "instancePath": "/b", 945 "schemaPath": "/properties/b/type" }, 946 { "instancePath": "/c", 947 "schemaPath": "/optionalProperties/c/type" }, 948 ] 949 These are the same errors as before, except the final error 950 (associated with the additional member named "e" in the instance) is 951 no longer present. This is because "additionalProperties: true" 952 enables "allow additional properties" mode on the schema. 954 3.3.7. Values 956 The elements form is meant to describe instances that are JSON 957 objects being used as an associative array. 959 If a schema is of the values form, then let _S_ be the value of the 960 schema member with the name "values". The instance is accepted if 961 and only if all of the following are true: 963 o The instance is an object. Otherwise, the standard error for this 964 case shall have an "instancePath" pointing to the instance, and a 965 "schemaPath" pointing to the schema member with the name "values". 967 o If the instance is an object, then every member value of the 968 instance must be accepted by _S_. Otherwise, the standard errors 969 for this case are the union of all the errors arising from 970 evaluating _S_ against member values of the instance. 972 For example, if we have the schema: 974 { 975 "values": { 976 "type": "float32" 977 } 978 } 980 Then the instances {} and {"a": 1, "b": 2} are accepted. If instead 981 we evaluate false against that schema, the standard errors are: 983 [{ "instancePath": "", "schemaPath": "/values" }] 985 Finally, if we evaluate the instance: 987 { "a": 1, "b": 2, "c": "foo", "d": 3, "e": "bar" } 989 The standard errors are: 991 [ 992 { "instancePath": "/c", "schemaPath": "/values/type" }, 993 { "instancePath": "/e", "schemaPath": "/values/type" } 994 ] 996 3.3.8. Discriminator 998 The discriminator form is meant to describe JSON objects being used 999 in a fashion similar to a discriminated union construct in C-like 1000 languages. When a schema is of the "discriminator" form, it 1001 validates: 1003 o That the instance is an object, 1005 o That the instance has a particular "tag" property, 1007 o That this "tag" property's value is a string within a set of valid 1008 values, and 1010 o That the instance satisfies another schema, where this other 1011 schema is chosen based on the value of the "tag" property. 1013 The behavior of the discriminator form is more complex than the other 1014 keywords. Readers familiar with CDDL may find the final example in 1015 Appendix A helpful in understanding its behavior. What follows in 1016 this section is a description of the discriminator form's behavior, 1017 as well as some examples. 1019 If a schema is of the "discriminator" form, then: 1021 o Let _D_ be the schema member with the name "discriminator". 1023 o Let _T_ be the member of _D_ with the name "tag". 1025 o Let _M_ be the member of _D_ with the name "mapping". 1027 o Let _I_ be the instance member whose name equals _T_'s value. _I_ 1028 may, for some rejected instances, not exist. 1030 o Let _S_ be the member of _M_ whose name equals _I_'s value. _S_ 1031 may, for some rejected instances, not exist. 1033 The instance is accepted if and only if: 1035 o The instance is an object. 1037 Otherwise, the standard error for this case shall have an 1038 "instancePath" pointing to the instance, and a "schemaPath" 1039 pointing to _D_. 1041 o If the instance is a JSON object, then _I_ must exist. 1043 Otherwise, the standard error for this case shall have an 1044 "instancePath" pointing to the instance, and a "schemaPath" 1045 pointing to _T_. 1047 o If the instance is a JSON object and _I_ exists, _I_'s value must 1048 be a string. 1050 Otherwise, the standard error for this case shall have an 1051 "instancePath" pointing to _I_, and a "schemaPath" pointing to 1052 _T_. 1054 o If the instance is a JSON object and _I_ exists and has a string 1055 value, then _S_ must exist. 1057 Otherwise, the standard error for this case shall have an 1058 "instancePath" pointing to _I_, and a "schemaPath" pointing to 1059 _M_. 1061 o If the instance is a JSON object, _I_ exists, and _S_ exists, then 1062 the instance must satisfy _S_'s value. By Section 2, _S_'s value 1063 must have the properties form. Apply the "discriminator tag 1064 exemption" afforded in Section 3.3.6 to _I_ when evaluating 1065 whether the instance satisfies _S_'s value. 1067 Otherwise, the standard errors for this case shall be standard 1068 errors from evaluating _S_'s value against the instance, with the 1069 "discriminator tag exemption" applied to _I_. 1071 Each of the list items above are defined to be mutually exclusive. 1072 For the same instance and schema, only one of the list items above 1073 will apply. 1075 To illustrate the discriminator form, if we have the schema: 1077 { 1078 "discriminator": { 1079 "tag": "version", 1080 "mapping": { 1081 "v1": { 1082 "properties": { 1083 "a": { "type": "float32" } 1084 } 1085 }, 1086 "v2": { 1087 "properties": { 1088 "a": { "type": "string" } 1089 } 1090 } 1091 } 1092 } 1093 } 1095 Then if we evaluate the instance: 1097 "example" 1099 Against this schema, the standard errors are: 1101 [{ "instancePath": "", "schemaPath": "/discriminator" }] 1103 (This is the case of the instance not being an object.) 1105 If we instead evaluate the instance: 1107 {} 1109 Then the standard errors are: 1111 [{ "instancePath": "", "schemaPath": "/discriminator/tag" }] 1113 (This is the case of _I_ not existing.) 1115 If we instead evaluate the instance: 1117 { "version": 1 } 1119 Then the standard errors are: 1121 [{ "instancePath": "/version", "schemaPath": "/discriminator/tag" }] 1123 (This is the case of _I_ existing, but having a string value.) 1124 If we instead evaluate the instance: 1126 { "version": "v3" } 1128 Then the standard errors are: 1130 [ 1131 { "instancePath": "/version", 1132 "schemaPath": "/discriminator/mapping" } 1133 ] 1135 (This is the case of _I_ existing and having a string value, but _S_ 1136 not existing.) 1138 If the instance evaluated were: 1140 { "version": "v2", "a": 3 } 1142 Then the standard errors are: 1144 [ 1145 { 1146 "instancePath": "/a", 1147 "schemaPath": "/discriminator/mapping/v2/properties/a/type" 1148 } 1149 ] 1151 (This is the case of _I_ and _S_ existing, but the instance not 1152 satisfying _S_'s value.) 1154 Finally, if instead the instance were: 1156 { "version": "v2", "a": "foo" } 1158 Then the instance satisfies the schema. No standard errors are 1159 returned. This is the case despite the fact that "version" is not 1160 mentioned by "/discriminator/mapping/v2/properties"; the 1161 "discriminator tag exemption" ensures that "version" is not treated 1162 as an additional property when evaluating the instance against _S_'s 1163 value. 1165 4. IANA Considerations 1167 No IANA considerations. 1169 5. Security Considerations 1171 Implementations of JDDF will necessarily be manipulating JSON data. 1172 Therefore, the security considerations of [RFC8259] are all relevant 1173 here. 1175 Implementations which evaluate user-inputted schemas SHOULD implement 1176 mechanisms to detect, and abort, circular references which might 1177 cause a naive implementation to go into an infinite loop. Without 1178 such mechanisms, implementations may be vulnerable to denial-of- 1179 service attacks. 1181 6. References 1183 6.1. Normative References 1185 [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 1186 Requirement Levels", BCP 14, RFC 2119, 1187 DOI 10.17487/RFC2119, March 1997, 1188 . 1190 [RFC3339] Klyne, G. and C. Newman, "Date and Time on the Internet: 1191 Timestamps", RFC 3339, DOI 10.17487/RFC3339, July 2002, 1192 . 1194 [RFC6901] Bryan, P., Ed., Zyp, K., and M. Nottingham, Ed., 1195 "JavaScript Object Notation (JSON) Pointer", RFC 6901, 1196 DOI 10.17487/RFC6901, April 2013, 1197 . 1199 [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 1200 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, 1201 May 2017, . 1203 [RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data 1204 Interchange Format", STD 90, RFC 8259, 1205 DOI 10.17487/RFC8259, December 2017, 1206 . 1208 [RFC8610] Birkholz, H., Vigano, C., and C. Bormann, "Concise Data 1209 Definition Language (CDDL): A Notational Convention to 1210 Express Concise Binary Object Representation (CBOR) and 1211 JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610, 1212 June 2019, . 1214 6.2. Informative References 1216 [I-D.handrews-json-schema] 1217 Wright, A. and H. Andrews, "JSON Schema: A Media Type for 1218 Describing JSON Documents", draft-handrews-json-schema-01 1219 (work in progress), March 2018. 1221 [RFC7071] Borenstein, N. and M. Kucherawy, "A Media Type for 1222 Reputation Interchange", RFC 7071, DOI 10.17487/RFC7071, 1223 November 2013, . 1225 [RFC7493] Bray, T., Ed., "The I-JSON Message Format", RFC 7493, 1226 DOI 10.17487/RFC7493, March 2015, 1227 . 1229 Appendix A. Comparison with CDDL 1231 This appendix is not normative. 1233 To aid the reader familiar with CDDL, this section illustrates how 1234 JDDF works by presenting JDDF schemas and CDDL schemas which accept 1235 and reject the same instances. 1237 The JDDF schema {} accepts the same instances as the CDDL rule: 1239 root = any 1241 The JDDF schema: 1243 { 1244 "definitions": { 1245 "a": { "elements": { "ref": "b" }}, 1246 "b": { "type": "float32" } 1247 }, 1248 "elements": { 1249 "ref": "a" 1250 } 1251 } 1253 Corresponds to the CDDL schema: 1255 root = [* a] 1257 a = [* b] 1258 b = number 1260 The JDDF schema: 1262 { "enum": ["PENDING", "DONE", "CANCELED"]} 1264 Accepts the same instances as the CDDL rule: 1266 root = "PENDING" / "DONE" / "CANCELED" 1268 The JDDF schema {"type": "boolean"} corresponds to the CDDL rule: 1270 root = bool 1272 The JDDF schemas {"type": "float32"} and {"type": "float64"} both 1273 correspond to the CDDL rule: 1275 root = number 1277 The JDDF schema {"type": "string"} corresponds to the CDDL rule: 1279 root = tstr 1281 The JDDF schema {"type": "timestamp"} corresponds to the CDDL rule: 1283 root = tdate 1285 The JDDF schema: 1287 { "elements": { "type": "float32" }} 1289 Corresponds to the CDDL rule: 1291 root = [* number] 1293 The JDDF schema: 1295 { 1296 "properties": { 1297 "a": { "type": "boolean" }, 1298 "b": { "type": "float32" } 1299 }, 1300 "optionalProperties": { 1301 "c": { "type": "string" }, 1302 "d": { "type": "timestamp" } 1303 } 1304 } 1306 Corresponds to the CDDL rule: 1308 root = { a: bool, b: number, ? c: tstr, ? d: tdate } 1309 The JDDF schema: 1311 { "values": { "type": "float32" }} 1313 Corresponds to the CDDL rule: 1315 root = { * tstr => number } 1317 Finally, the JDDF schema: 1319 { 1320 "discriminator": { 1321 "tag": "a", 1322 "mapping": { 1323 "foo": { 1324 "properties": { 1325 "b": { "type": "float32" } 1326 } 1327 }, 1328 "bar": { 1329 "properties": { 1330 "b": { "type": "string" } 1331 } 1332 } 1333 } 1334 } 1335 } 1337 Corresponds to the CDDL rule: 1339 root = { a: "foo", b: number } / { a: "bar", b: tstr } 1341 Appendix B. Examples 1343 This appendix is not normative. 1345 As a demonstration of JDDF, here is a JDDF schema closely equivalent 1346 to the plain-English definition "reputation-object" described in 1347 Section 6.2.2 of [RFC7071]: 1349 { 1350 "properties": { 1351 "application": { "type": "string" }, 1352 "reputons": { 1353 "elements": { 1354 "additionalProperties": true, 1355 "properties": { 1356 "rater": { "type": "string" }, 1357 "assertion": { "type": "string" }, 1358 "rated": { "type": "string" }, 1359 "rating": { "type": "float32" }, 1360 }, 1361 "optionalProperties": { 1362 "confidence": { "type": "float32" }, 1363 "normal-rating": { "type": "float32" }, 1364 "sample-size": { "type": "float64" }, 1365 "generated": { "type": "float64" }, 1366 "expires": { "type": "float64" } 1367 } 1368 } 1369 } 1370 } 1371 } 1373 This schema does not enforce the requirement that "sample-size", 1374 "generated", and "expires" be unbounded positive integers. It does 1375 not express the limitation that "rating", "confidence", and "normal- 1376 rating" should not have more than three decimal places of precision. 1378 This can be compared against the equivalent example in Appendix H of 1379 [RFC8610]. 1381 Acknowledgments 1383 Thanks to Gary Court, Francis Galiegue, Kris Zyp, Geraint Luff, Jason 1384 Desrosiers, Daniel Perrett, Erik Wilde, Ben Hutton, Evgeny 1385 Poberezkin, Brad Bowman, Gowry Sankar, Donald Pipowitch, Dave Finlay, 1386 Denis Laxalde, Henry Andrews, and Austin Wright for their work on the 1387 initial drafts of JSON Schema, which inspired JSON Data Definition 1388 Format. 1390 Thanks to Tim Bray, Carsten Bormann, and James Manger for their help. 1392 Author's Address 1394 Ulysse Carion 1396 Email: ulyssecarion@gmail.com