This document is the full spec for the Refract, a recursive data structure for expressing complex structures, relationships, and metadata.
This document conforms to RFC 2119, which says:
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.
MSON is used throughout this document to describe and define data structures.
Refract provides a single structure for data, which will be referred to throughout this document as an element. All elements found in a Refract document SHOULD conform to the element structure as defined here.
The Refract Element contains four properties: element
, meta
, attributes
, and content
, as defined below. This Element MAY be used recursively throughout the document, even as a value for each of its own meta or attributes.
-
element
(string, required)The
element
property defines the name of element. It MUST be a string that references an element, which SHOULD be defined. -
meta
(enum)The
meta
property is a reserved object for Refract-specific values. Whenmeta
is an object, it MAY contain elements itself. The element definition SHOULD be used when interacting withmeta
and its properites and values.- Members
- (object)
id
- Unique Identifier, MUST be unique throughout the documentref
(Link) - Link to referenced element or typeclass
(array[string]) - Array of classifications for given elementprefix
(string) - Prefix in which element MAY be foundname
(enum) - For use when an element is used as a property (or key/value pair)- (string)
- (Element)
namespaces
(array[Link]) - Include elements from given namespaces or prefix elements from given namespacetitle
(string) - Human-readable title of elementdescription
(string) - Human-readable description of element
- (array[Property Element])
- (object)
- Members
-
attributes
(enum)The
attributes
property defines attributes about the given instance of the element, as specified by theelement
property. Whenattributes
is an object, it MAY contain elements itself. The element definition SHOULD be used when interacting withattributes
and its properites and values.- Members
- (object)
- (array[Property Element])
- Members
-
content
(enum)The
content
property defines the content of the instance of the specified element. The value MAY be any of the Refract primitive types.- Members
- (null)
- (string)
- (number)
- (boolean)
- (array)
- (object)
- (Element)
- Members
An element MAY look like this, where foo
is the element name, id
is a meta attribute for the foo
element, and content
is a string with a value of bar
. Here, the id
is baz
and MAY be used for referencing.
{
"element": "foo",
"meta": {
"id": "baz"
},
"content": "bar"
}
In addition to expressing Refract Elements as objects with element
, meta
, attributes
, and content
properties, these elements MUST be expressed as a tuple.
The Compact Element is a tuple where each item has a specific meaning. The first item is the element name, the second is the meta attribute section, the third is the attribute section, and the fourth is the content section.
- (string, required) - Name of the element
- (enum, required) - Meta attributes of the element instance. See meta attributes above for full Refract representation
- (object)
- (array[Compact Element])
- (enum, required) - Attributes of the element instance
- (object)
- (array[Compact Element])
- (enum, required) - Element content with any of the following types
- (null)
- (string)
- (number)
- (boolean)
- (array)
- (object)
- (Compact Element)
- (array[Compact Element])
Below is a Refract element foo
that is expressed in the normal Refract representation.
{
"element": "foo",
"content": "bar"
}
This is how it would represented in the compact version.
["foo", {}, {}, "bar"]
Primitive Elements extend upon the base Element to define elements based on the Primitive Types of Refract.
A Refract document MUST support each of these primitive elements. These elements MAY be extended or replaced based on namespaces provided in any root or parent element.
A Null Element
is an element that has a Null Type as its value. It extends upon the Refract Element.
element
: null (string, fixed)content
(null)
In JSON, null
is represented as null
.
null
In Refract, it is represented as a Null Element
element.
{
"element": "null",
"content": null
}
A String Element provides an element for Refract String Types.
element
: string (string, fixed)content
(string)
In JSON, an example of a string is:
"foobar"
In Refract, this string is expanded to a String Element.
{
"element": "string",
"content": "foobar"
}
A Number Element provides an element for Refract Number Types.
element
: number (string, fixed)content
(number)
In JSON, a number is represented as:
400
In Refract, this number is expanded to a Number Element.
{
"element": "number",
"content": 400
}
A Boolean Element provides an element for Refract Boolean Types.
element
: boolean (string, fixed)content
(boolean)
In JSON, an example of a boolean is:
true
In Refract, this boolean is expanded to a Boolean Element.
{
"element": "boolean",
"content": true
}
An Array Element provides an element for Refract Array Types.
element
: array (string, fixed)content
(array[Element])
In JSON, an example of an array is:
["abc", 400, true]
In Refract, this boolean is expanded to a Array Element.
{
"element": "array",
"content": [
{
"element": "string",
"content": "foo"
},
{
"element": "number",
"content": 400
},
{
"element": "boolean",
"content": true
}
]
}
A Object Element provides an element for Refract Object Types. When the content of an object
element includes an extend
, select
, or ref
element, the referenced or resulting elements MUST be a property
element. The properties of the object SHOULD be unique to the object in which they are found.
element
: object (string, fixed)content
(enum)- (object)
- (array[Property Element])
- (Extend Element)
- (Select Element)
- (Ref Element)
In JSON, an example of an object is:
{
"foo": "bar"
}
In Refract, this object MAY Be expanded to include an array of elements as its content.
{
"element": "object",
"content": [
{
"element": "string",
"meta": {
"name": "foo"
},
"content": "bar"
}
]
}
A property element is any element with a name
meta attribute value. Properties are to provide a key-value pair. See Object Element for examples of how this is used.
While the name of a property MAY be a string, it MAY also be an element for use in element and type information about the property name.
meta
name
(enum, required) - Name of property given- (string)
- (Element)
These elements and definitions are provided as part of the base specification for the purpose of identifying, referencing, and linking to elements.
The ref
element MAY be used to reference elements in remote documents or elements in the local document. The ref
element transcludes the contents of the element into the document in which it is referenced.
element
ref (string, fixed)content
(Link, required)
Elements MAY be referenced in remote or local documents.
{
"element": "ref",
"content": "http://example.com/document#foo"
}
{
"element": "ref",
"content": "foo"
}
This references the element with the ID of foo
in the prefixed namespace of ns
.
{
"element": "ref",
"content": {
"prefix": "ns",
"href": "foo"
}
}
Given an element instance of:
{
"element": "array",
"meta": {
"id": "colors"
},
"content": [
{
"element": "string",
"content": "red"
},
{
"element": "string",
"content": "green"
}
]
}
And given an array where a reference is used as:
{
"element": "array",
"content": [
{
"element": "string",
"content": "blue"
},
{
"element": "ref",
"content": {
"href": "colors",
"path": "content"
}
}
]
}
The resulting dereferenced array is:
{
"element": "array",
"content": [
{
"element": "string",
"content": "blue"
},
{
"element": "string",
"content": "red"
},
{
"element": "string",
"content": "green"
}
]
}
A link is an object for providing URLs to local elements, prefixed elements, and remote elements or documents. The following rules apply.
- When referencing an element in the local namespace, the
id
of the element MAY be used - When referencing remote elements, an absolute URL or relative URL MAY be used
- When a URL fragment exists in the URL given, it references the element with the matching
id
in the given namespace. The URL fragment MAY need to be URL decoded before making a match. - When a URL fragment does not exist, the URL references the root element
- When the
prefix
is used, it references an element in a defined prefixed namespace - When
path
is used, it references the given property of the referenced element - When
path
is used in an element that includes the data of the link (such as withref
), the referenced path MAY need to be converted to a refract structure in order to be valid
- (string) - A URL to a namespace or an ID of an element in the current namespace
- (object) - A prefixed link
prefix
(string) - Prefix of namespacehref
(string, required) - URL or ID of element in prefixed namespacepath
(enum) - Path of referenced element to transclude instead of element itself- meta - The meta data of the referenced element
- attributes - The attributes of the referenced element
- content - The content of the referenced element
Namespaces provide a way to include element definitions and constraints into another document. The following rules and constraints apply to namespaces.
- If there is a conflict, the namespaced element defined or referenced last MUST take precedence
- Types defined within the local namespace MUST take precedence over referenced namespaces
- Prefixed namespaces are only accessible through using a prefix
- Namespaces apply to the element in which they are introduced and all child elements
- Namespaces MUST not include the elements nor the data in the elements referenced, but rather include the constraints and conditions around the types defined within that namespace
This example shows a namespace being included by way of a string, and a prefixed namespace.
{
"element": "foo",
"meta": {
"namespaces": [
"http://example.com/namespace1",
{ "prefix": "ns2", "href": "http://example.com/namespace2" }
]
}
}
Elements by default do not include any of the attributes or content from the element in which they reference. An element MAY be extended in order to inherit from other elements using the extend
element.
Additionally, the select
element is provided to give multiple possibilities for a given content.
The extend
element provides a way to a way to multiply inherit one or more elements to form a new element. The extend
element MUST NOT affect the original elements being extended, and MUST define a new instance of an element.
The extend
element MUST do a deep merge of the elements found in the content
, but MUST NOT include any meta
attributes from the content elements in the final element. Each element found in the content
MUST derive from the same primitive element. The elements are merged from first to last.
element
extend (string, fixed)content
(array[Element]) - Array of elements to be merged
{
"element": "extend",
"content": [
{
"element": "foo",
"attributes": {
"baz": "bar"
},
"content": "first"
},
{
"element": "foo",
"content": "second"
}
]
}
The value for this new element would be the following.
{
"element": "foo",
"attributes": {
"baz": "bar"
},
"content": "second"
}
Elements MAY also be referenced when using extend. Here is an element defined and given an ID of bar
.
{
"element": "foo",
"meta": {
"id": "bar"
},
"content": "second"
}
Here is an extend element referencing the previously bar
element.
{
"element": "extend",
"content": [
{
"element": "foo",
"content": "first"
},
{
"element": "ref",
"content": "bar"
}
]
}
The resulting element would be the following. Note that the id
was not included in the final element.
{
"element": "foo",
"content": "second"
}
element
select (string, fixed)content
(array[Option Element])
This example uses a Select Element to provide multiple options for the properites of an Object Element. One option is the value of the the key firstName
is "John," and the other option is the value of the key giveName
is "John."
{
"element": "object",
"content": [
{
"element": "select",
"content": [
{
"element": "option",
"content": [
{
"element": "string",
"meta": {
"name": "firstName"
},
"content": "John"
}
]
},
{
"element": "option",
"content": [
{
"element": "string",
"meta": {
"name": "givenName"
},
"content": "John"
}
]
}
]
}
]
}
For the above example, if the first option is chosen, the resulting object will look like this:
{
"firstName": "John"
}
If the second option is chosen, it will look like this:
{
"givenName": "John"
}
The Option Element provides a way to give one or more elements that MAY be the value of the Select Element in which it is found. For examples, see the Select Element section.
element
option (string, fixed)content
(array[Element])
When an element is given an ID, it creates a new type of element. When instances of the new element are used, they MAY conform to the definition of the referenced element.
Elements do not inherit data from the referenced element, though they do inherit the definition. This means that a referenced element MAY define what an element MAY look like, but it does not define what it MUST look like, nor does it define data for each instance.
When it is desired to inherit attributes, use the Extend Element and Ref Element together to accomplish this.
The element below is a string element with an ID of "foo."
{
"element": "string",
"meta": { "id": "foo" },
"attributes": {
"bar": "baz"
},
"content": "Hello World"
}
Since an ID was given, foo
MAY now be used for creating new instances.
{
"element": "foo",
"content": "new instance"
}
What this says is that this element MAY have an attribute of bar
that is equal to baz
and MAY have content that is like "Hello World." The instance of foo
MUST not inherit any data from foo
, though it does inherit the definition of the element where the ID is foo
.