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.
The proposed media type for this spec are as follows.
application/vnd.refractfor Full Refractapplication/vnd.embedded-refractfor Embedded Refract
Any custom media type in this project SHOULD append the name of the profile to these base media types separated by a period (i.e. application/vnd.refract.my-custom-type).
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
elementproperty defines the name of element. It MUST be a string that references an element, which SHOULD be defined. -
meta(object)The
metaproperty is a reserved object for Refract-specific values. Whenmetais an object, it MAY contain elements itself. The element definition SHOULD be used when interacting withmetaand its properties and values.- Properties
id- Unique Identifier, MUST be unique throughout the documentref(Ref Element) - Pointer to referenced element or typeclasses(Array Element[String Element]) - Array of classifications for given elementtitle(String Element) - Human-readable title of elementdescription(String Element) - Human-readable description of elementlinks(Array Element[Link Element]) - Meta links for a given element
- Properties
-
attributes(object)The
attributesproperty defines attributes about the given instance of the element, as specified by theelementproperty.attributesvalues MUST be elements themselves. -
content(enum)The
contentproperty 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[Element])
- (Element)
- (Key Value Pair)
- 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": {
"element": "string",
"content": "baz"
}
},
"content": "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 profiles provided, either by way of a profile link relation or other means such as HTTP Link Headers.
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.
nullIn 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:
400In 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:
trueIn 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 member element. The properties of the object SHOULD be unique to the object in which they are found.
element: object (string, fixed)content(enum)- (array[Member 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": "member",
"content": {
"key": {
"element": "string",
"content": "foo"
},
"value": {
"element": "string",
"content": "bar"
}
}
}
]
}A Member Element is any element with a key-value pair as the content. See Object Element for examples of how this is used.
elementmember (string, fixed)content(Key Value Pair)key(Element, required) - Key for the membervalue(Element, optional) - Value for the member
These elements and definitions are provided as part of the base specification for the purpose of identifying, referencing, and pointing to elements and their respective meta, attributes, or content.
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.
A ref is an object for providing URLs to local elements and remote elements or documents. The following rules apply.
- When referencing an element in the local document, the
idof 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
idin the given document. 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
pathis used, it references the given property of the referenced element - When
pathis used in an element that includes the data of the pointer (such as withref), the referenced path MAY need to be converted to a refract structure in order to be valid
elementref (string, fixed)- attributes
path(enum[String Element]) - Path of referenced element to transclude instead of element itself- element (default) - The complete referenced element
- meta - The meta data of the referenced element
- attributes - The attributes of the referenced element
- content - The content of the referenced element
- content (required, string) - A URL to an ID of an element in the current document
Elements MAY be referenced in remote or local documents.
{
"element": "ref",
"content": "http://example.com/document#foo"
}{
"element": "ref",
"content": "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",
"attributes": {
"path": {
"element": "string",
"content": "content"
}
},
"content": "colors"
}
]
}The resulting dereferenced array is:
{
"element": "array",
"content": [
{
"element": "string",
"content": "blue"
},
{
"element": "string",
"content": "red"
},
{
"element": "string",
"content": "green"
}
]
}Hyperlinking MAY be used to link to other resources, provide links to instructions on how to process a given element (by way of a profile or other means), and may be used to provide meta data about the element in which it's found. The meaning and purpose of the hyperlink is defined by the link relation according to RFC 5988.
element: link (string, fixed)attributesrelation(string) - Link relation type as specified in RFC 5988.href(string) - The URI for the given link
The following shows a link with the relation of foo and the URL of /bar.
{
"element": "link",
"attributes": {
"relation": "foo",
"href": "/bar"
}
}The primary means by which users can provide semantic definitions and other meta information is through a profile. A profile MAY provide semantic information about an element and its data, it MAY provide specific instructions about elements such as how inheritance should work or how elements should be processed, and it MAY be used to modify understanding of existing elements in other profiles. The usage of a profile is not limited to these uses here, and SHOULD be left up to the profile author to define its use.
To point to a profile, you MAY use the profile link relation as a meta link in your root element or in any other element. Profile links may also be found outside of the document itself in places like the HTTP Link Header. Additionally, a profile link is not required in order to use the functionality a profile provides, as a media type MAY define the same things a profile.
Below is an example of how a profile link is used as a meta link in Refract.
{
"element": "foo",
"meta": {
"links": [
{
"element": "link",
"attributes": {
"relation": "profile",
"href": "http://example.com/profiles/foo"
}
}
]
},
"content": "bar"
}The example shows a foo element with a profile link. This profile link informs the parser this particular element is defined as part of the linked profile.
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 the id meta attribute 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.
elementextend (string, fixed)content(array[Element]) - Array of elements to be merged
{
"element": "extend",
"content": [
{
"element": "foo",
"attributes": {
"baz": {
"element": "string",
"content": "bar"
}
},
"content": "first"
},
{
"element": "foo",
"content": "second"
}
]
}The value for this new element would be the following.
{
"element": "foo",
"attributes": {
"baz": {
"element": "string",
"content": "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": {
"element": "string",
"content": "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"
}elementselect (string, fixed)content(array[Option Element])
This example uses a Select Element to provide multiple options for the properties 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": "member",
"content": {
"key": {
"element": "string",
"content": "firstName"
},
"value": {
"element": "string",
"content": "John"
}
}
}
]
},
{
"element": "option",
"content": [
{
"element": "member",
"content": {
"key": {
"element": "string",
"content": "givenName"
},
"value": {
"element": "string",
"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.
elementoption (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": {
"element": "string",
"content": "foo"
}
},
"attributes": {
"bar": {
"element": "string",
"content": "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.