diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1accb557a..df2d7287f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -352,6 +352,17 @@ The third schema is `third.schema.json`, it extends both `second`, and transitiv } ``` +### Schema Descriptors + +Schema descriptors are an extensible mechanism for providing additional metadata about an XDM schema. For example, schema descriptors can be used to define relationships between schemas or to annotate schema properties with additional metadata. Schema descriptors may be used when certain properties of a schema are not static (which could usually be described in the schema directly) but may vary from usage to usage. + +Details on using and defining schema descriptors may be found in the section [Schema Descriptors](./docs/descriptors.md) of the specification. + +Schema descriptors are extensible, and new descriptors may be creating by defining a new URI value and using it in +the `@type` property of the descriptor object. Readers should ignore descriptors they do not understand. + +Schema descriptors are defined in XDM using the `SchemaDescriptor` schema. + ### Structuring Schemas - Nesting versus Namespaces The use of JSON-LD namespaces in XDM means that schema definitions are organized around two axes. The first is the structure of the JSON, which may be nested to an arbitrary depth. The second is the orthogonal layer created by each independent namespace. While both organizing axes are available, it is important to use each for its intended purpose. @@ -375,6 +386,7 @@ XDM is using a couple of custom keywords that are not part of the JSON Schema st * `meta:extensible`: see above, to describe schemas that allow custom properties * `meta:auditable`: for schemas that have created and last modified dates +* `meta:descriptors`: to annotate schemas with additional metadata (see Schema Descriptors above) * `meta:enum`: for known values in enums, strings, and as property keys ## Writing Styleguides diff --git a/docs/descriptors.md b/docs/descriptors.md new file mode 100644 index 000000000..2578e191f --- /dev/null +++ b/docs/descriptors.md @@ -0,0 +1,158 @@ +# Schema Descriptors + +## Overview + +XDM allows for additional metadata about a schema to be described using a "schema descriptor". A schema descriptor is applied to a schema using the "meta:descriptors" property. Descriptors may be embedded directly in the schema document, or may be described as independent external entities. The ability to define descriptors outside of a schema is useful for, among other things, annotating schemas that are not under an application's direct control with additional metadata. See examples below. + +Schema descriptors are extensible, and new descriptors may be created by defining a new URI value and using it in +the `@type` property of the descriptor object. Readers should ignore descriptors they do not understand. + +Schema descriptors are defined in XDM using the `SchemaDescriptor` schema. + +## Defining Schema Relationships + +While schema descriptors can be used to define metadata about a single schema, they are also common used to describe relationships between schemas. This mechanism can be used to link schemas together at the property level, defining the equivalent of "foreign key" relationships in a relational database. + +The following relationship types are defined by XDM: + +TBD + +## Update Policies + +TBD + +## Other Supported Schema Descriptors + +TBD + +## Embedding Schema Descriptors in a Schema + +The `SchemaDescriptor` schema is designed such that a descriptor can be fully defined as a standalone entity, or embedded in the schema it is describing. When embedded, a schema descriptor may be placed at the root of the schema (which is appropriate for a descriptor that applies to the whole schema) or placed on the sub-schema for a specific property (which is appropriate when the descriptor applies to a property). + +In some cases, a descriptor may describe a symmetric relationship. For example, an `xdm:oneToOne` relationship is true for both the source and the destination properties. In this case, it is recommended that descriptors be placed on both the source and the destination. + +Examples for each of these cases are shown below. + +## Schema Descriptor Examples + +### Example Relationship Descriptor + +We have two schemas, which form a parent/child relationship. The first is parent.json: + +```json +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "$id": "https://ns.adobe.com/xdm/example/parent", + "title": "Parent", + "type": "object", + "properties": { + "@id": { + "meta:descriptors": [ + { + "@type": "xdm:oneToMany", + "xdm:destinationSchema": "https://ns.adobe.com/xdm/example/child", + "xdm:destinationProperty": "xdm:parent" + } + ], + "type": "string" + } + } +} +``` + +The second is child.json: + +```json +{ + "$schema": "http://json-schema.org/draft-06/schema#", + "$id": "https://ns.adobe.com/xdm/example/child", + "title": "Child", + "type": "object", + "properties": { + "@id": { "type": "string" }, + "xdm:parent": { + "meta:descriptors": [ + { + "@type": "xdm:manyToOne", + "xdm:destinationSchema": "https://ns.adobe.com/xdm/example/parent", + "xdm:destinationProperty": "@id" + } + ], + "type": "string", + "format": "uri" + } + } +} +``` + +The source schema in this example is Parent, which contains a single relationship descriptor describing a one-to-many relationship between objects of schema Parent to objects of schema Child. + +The above example shows how a descriptor may be embedded in the schema being described, directly on the property where it applies. The example also shows the reciprocal relationship between the parent and child entities. If we were to define this as a stand-alone descriptor, it would look like this: + +```json +{ + "@id": "https://example.com/descriptors/1", + "@type": "xdm:oneToMany", + "xdm:sourceSchema": "https://ns.adobe.com/xdm/example/parent", + "xdm:sourcePropery": "@id", + "xdm:destinationSchema": "https://ns.adobe.com/xdm/example/child", + "xdm:destinationProperty": "xdm:parent" +} +``` + +This highlights the ability to use schema descriptors both directly in schemas and also as independent entities. + +### Example of Defining a New Schema Descriptor + +Let's say Example.com would like to annotate their schemas with information on whether they are actively being used in their application, a cloud service. They'd like to know if the schema is being used in production, in staging, or is unused. + +They need to do two things to define the new descriptor. First, they create a new URI to define the type of the descriptor: 'https://ns.example.com/descriptors/inuse'. + +Next, they define an extension to `SchemaDescriptor` containing the in-use flag: + +```json +{ + "$id": "https://ns.example.com/xdm/inusedescriptor", + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "In Use Descriptor", + "meta:extends": [ + "https://ns.adobe.com/xdm/common/schemadescriptor#/definitions/descriptor" + ], + "meta:abstract": false, + "type": "object", + "description": "where is this schema being used?", + "definitions": { + "inusedescriptor": { + "properties": { + "xdm:usage": { + "title": "Usage", + "type": "string", + "description": "the usage state of the schema", + "enum": ["production", "stage", "none"] + } + }, + "required": ["xdm:usage"] + } + }, + "allOf": [ + { + "$ref": + "https://ns.adobe.com/xdm/common/schemadescriptor#/definitions/descriptor" + }, + { + "$ref": "#/definitions/inusedescriptor" + } + ] +} +``` + +Applying this descriptor might look like: + +```json +{ + "@id": "https://example.com/descriptors/4", + "@type": "https://ns.example.com/descriptors/inuse", + "xdm:sourceSchema": "https://ns.example.com/xdm/salesorder", + "xdm:usage": "production" +} +``` diff --git a/meta.schema.json b/meta.schema.json index 96c4d0751..4afc3c41c 100644 --- a/meta.schema.json +++ b/meta.schema.json @@ -71,6 +71,14 @@ } ] }, + "meta:descriptors": { + "type": "array", + "items": { + "type": "object", + "$ref": + "https://ns.adobe.com/xdm/common/desciptors/schemadescriptor#/definitions/descriptor" + } + }, "type": { "type": "string", "const": "object" diff --git a/package.json b/package.json index 6f5bc30e3..00f90c94f 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "aem_user": "packageUser", "aem_password": "override me securely", "markdown-importer-version": "0.0.4", - "schemas": 137 + "schemas": 139 }, "scripts": { "clean": "rm -rf docs/reference", diff --git a/schemas/common/descriptors/itemselector.description.md b/schemas/common/descriptors/itemselector.description.md new file mode 100644 index 000000000..b9be1b933 --- /dev/null +++ b/schemas/common/descriptors/itemselector.description.md @@ -0,0 +1,3 @@ +Describes how to select or match to a specific item from an array of values described by an XDM schema. + +Matching may be done based on array index, `@id`, `@type`, or schema URI. diff --git a/schemas/common/descriptors/itemselector.example.1.json b/schemas/common/descriptors/itemselector.example.1.json new file mode 100644 index 000000000..c7042b47c --- /dev/null +++ b/schemas/common/descriptors/itemselector.example.1.json @@ -0,0 +1,3 @@ +{ + "xdm:id": "https://example.com/objects/12345" +} diff --git a/schemas/common/descriptors/itemselector.example.2.json b/schemas/common/descriptors/itemselector.example.2.json new file mode 100644 index 000000000..f495f5b1f --- /dev/null +++ b/schemas/common/descriptors/itemselector.example.2.json @@ -0,0 +1,3 @@ +{ + "xdm:type": "https://ns.adobe.com/experience/mcid" +} diff --git a/schemas/common/descriptors/itemselector.example.3.json b/schemas/common/descriptors/itemselector.example.3.json new file mode 100644 index 000000000..7a03d7f6c --- /dev/null +++ b/schemas/common/descriptors/itemselector.example.3.json @@ -0,0 +1,3 @@ +{ + "xdm:index": 0 +} diff --git a/schemas/common/descriptors/itemselector.example.4.json b/schemas/common/descriptors/itemselector.example.4.json new file mode 100644 index 000000000..224a0aba2 --- /dev/null +++ b/schemas/common/descriptors/itemselector.example.4.json @@ -0,0 +1,3 @@ +{ + "xdm:schema": "https://ns.adobe.com/xdm/context/identity" +} diff --git a/schemas/common/descriptors/itemselector.schema.json b/schemas/common/descriptors/itemselector.schema.json new file mode 100644 index 000000000..6bd581736 --- /dev/null +++ b/schemas/common/descriptors/itemselector.schema.json @@ -0,0 +1,75 @@ +{ + "meta:license": [ + "Copyright 2018 Adobe Systems Incorporated. All rights reserved.", + "This work is licensed under a Creative Commons Attribution 4.0 International (CC BY 4.0) license", + "you may not use this file except in compliance with the License. You may obtain a copy", + "of the License at https://creativecommons.org/licenses/by/4.0/" + ], + "$id": "https://ns.adobe.com/xdm/common/descriptors/itemselector", + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Item Selector", + "meta:extensible": false, + "meta:abstract": false, + "type": "object", + "description": + "Describes how to select or match to a specific item from an array of values described by an XDM schema. Matching may be done based on array index, @id, @type, or schema URI.", + "definitions": { + "selector": { + "oneOf": [ + { + "properties": { + "xdm:index": { + "title": "Index", + "type": "integer", + "description": + "When present, indicates the item at this array index should be selected.", + "minimum": 0 + } + }, + "required": ["xdm:index"] + }, + { + "properties": { + "xdm:id": { + "title": "ID", + "type": "string", + "format": "uri", + "description": + "When present, indicates the item with this @id value should be selected." + } + }, + "required": ["xdm:id"] + }, + { + "properties": { + "xdm:type": { + "title": "Type", + "type": "string", + "format": "uri", + "description": + "When present, indicates the item with this @type value should be selected." + } + }, + "required": ["xdm:type"] + }, + { + "properties": { + "xdm:schema": { + "title": "Schema", + "type": "string", + "format": "uri", + "description": + "When present, indicates the item which conforms to this schema URI should be selected." + } + }, + "required": ["xdm:schema"] + } + ] + } + }, + "allOf": [ + { + "$ref": "#/definitions/selector" + } + ] +} diff --git a/schemas/common/descriptors/schemadescriptor.example.1.json b/schemas/common/descriptors/schemadescriptor.example.1.json new file mode 100644 index 000000000..bc0f861f9 --- /dev/null +++ b/schemas/common/descriptors/schemadescriptor.example.1.json @@ -0,0 +1,9 @@ +{ + "@id": "https://example.com/descriptors/1", + "@type": "xdm:descriptorPrimaryKey", + "xdm:source": "https://ns.adobe.com/xdm/context/profile", + "xdm:sourceProperty": "xdm:identities", + "xdm:sourceItem": { + "xdm:type": "https://ns.adobe.com/experience/mcid" + } +} diff --git a/schemas/common/descriptors/schemadescriptor.schema.json b/schemas/common/descriptors/schemadescriptor.schema.json new file mode 100644 index 000000000..d3e206ddb --- /dev/null +++ b/schemas/common/descriptors/schemadescriptor.schema.json @@ -0,0 +1,63 @@ +{ + "meta:license": [ + "Copyright 2018 Adobe Systems Incorporated. All rights reserved.", + "This work is licensed under a Creative Commons Attribution 4.0 International (CC BY 4.0) license", + "you may not use this file except in compliance with the License. You may obtain a copy", + "of the License at https://creativecommons.org/licenses/by/4.0/" + ], + "$id": "https://ns.adobe.com/xdm/common/desciptors/schemadescriptor", + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Schema Descriptor", + "meta:extensible": true, + "meta:abstract": false, + "type": "object", + "description": + "A descriptor that contains metadata about an XDM schema, including an optional property and array item selector, used to address the descriptor to a specific property or item.", + "definitions": { + "descriptor": { + "properties": { + "@id": { + "title": "Identifier", + "type": "string", + "format": "uri", + "description": + "The unique identifier for the schema descriptor. This property is required when the descriptor is defined outside of the applicable schema, but is optional when applied via 'meta:descriptors'" + }, + "@type": { + "title": "Type", + "type": "string", + "description": "The type of descriptor this object represents", + "meta:enum": {} + }, + "xdm:sourceSchema": { + "title": "Source Schema", + "type": "string", + "format": "uri", + "description": + "The source schema this descriptor applies to. This property is required when the descriptor is defined outside of the applicable schema, but is optional when applied via 'meta:descriptors'" + }, + "xdm:sourceProperty": { + "title": "Source Property", + "type": "string", + "description": + "When present, the property of the source schema to which this descriptor applies. This value is a JSON Pointer, applied to an instance of an object described by `xdm:sourceSchema`." + }, + "xdm:sourceItem": { + "title": "Source Item", + "description": + "When present, the selector used to match a specific item in the array pointed to by `sourceProperty`", + "$ref": + "https://ns.adobe.com/xdm/common/descriptors/itemselector#/definitions/selector" + } + } + } + }, + "allOf": [ + { + "$ref": "https://ns.adobe.com/xdm/common/extensible#/definitions/@context" + }, + { + "$ref": "#/definitions/descriptor" + } + ] +}