Collection.next+JSON - Document Format
Lightweight hypermedia type for read/write Hypermedia/RESTful/HTTP APIs
Description
Collection.next+JSON is a JSON-based read/write hypermedia-type designed to support management and querying of nested data collections. Collection.next+JSON is an extension of Collection+JSON hypermedia format.
- Author:
- Ioseb Dzmanashvili (ioseb.dzmanashvili@gmail.com)
- Dates:
- 2012-03-26 (Created)
- Status:
- application/vnd.collection.next+json (Approved)
Contents
NOTE:
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 RFC2119.
NOTE:
The data type names "OBJECT", "ARRAY", "NUMBER", "STRING", and "VALUE" in this document are to be interpreted as described in Collection+JSON specification.
1. General Concepts and Goals
Section defines general concepts describing all extensions to Collection+JSON specification.
Main goal of this extension is to improve existing capabilities of Collection+JSON further and add more power and expressiveness to existing features of specification.
Extension introduces several new objects, arrays and properties and adds more flexibility and semantics to various areas of base specification.
When Collection.next+JSON document format is used for implementing APIs application/vnd.collection.next+json
MUST be used as a value of the
Accept and
Content-Type headers as shown in the examples below:
// sample POST request
*** REQUEST ***
POST /my-collection/ HTTP/1.1
Host: www.example.org
Content-Type: application/vnd.collection.next+json
Content-Length: ...
{
"template": {OBJECT}
}
OR
// sample GET request
*** REQUEST ***
GET /my-collection/ HTTP/1.1
Host: www.example.org
Accept: application/vnd.collection.next+json
2. Objects
An object is an unordered collection of zero or more name/value
pairs, where a name is a string and a value is a string
, number
,
boolean
, null
, object
, or array
.
Extension defines new set of objects. They are: the list, status, method and enctype.
2.1. list
The list object is a child property of the data array elements.
The list object MAY contain any of three possible properties: options (REQUIRED), multiple (OPTIONAL) and default (OPTIONAL).
If the list object is specified and it doesn't contain the multiple property clients SHOULD only use one of the values provided by the options array.
If the list object is specified and it contains
the multiple property which value is specified to true
,
clients MAY use any possible combination of multiple values provided by
the options array.
2.1.1 Using the list object with query templates
Section describes possible behavior of using the list object within query templates.
// sample query template with list object
{
"queries": [
{
"href": "http://service.com/my-resource",
"rel": "search",
"prompt": "Enter search string",
"data" : [
{
"name": "gender",
"prompt": "gender",
"list": {
"options": [
{"value": "female", "prompt": "Female"},
{"value": "male", "prompt": "Male"}
]
}
}
]
}
]
}
There are two possible outcomes based on the example above and resulting queries are as follows:
-
http://service.com/my-resource?gender=female
-
http://service.com/my-resource?gender=male
If the multiple
property present and it's value is specified to true
as shown in the following example:
// sample query template with list object and multiple property
{
"queries": [
{
"href": "http://service.com/my-resource",
"rel": "search",
"prompt": "Enter search string",
"data" : [
{
"name": "gender",
"prompt": "gender",
"list": {
"multiple": true,
"options": [
{"value": "female", "prompt": "Female"},
{"value": "male", "prompt": "Male"}
]
}
}
]
}
]
}
Possible outcomes of resulting queries would be as follows:
-
http://service.com/my-resource?gender=male&gender=female
-
http://service.com/my-resource?gender=female
-
http://service.com/my-resource?gender=male
2.1.1 Using the list object in the template object
Section describes possible behavior of using the list object when used with the template object.
If the multiple
property present and it's value is specified to true
as shown in following example:
// sample template object with list object and type property
{"collection": {
"version": 1.0,
"template": {
"data" : [
{
"name": "interests",
"prompt": "Interests",
"list": {
"multiple": true,
"options": [
{"value": "sports", "prompt": "Sports"},
{"value": "music", "prompt": "Music"}
]
}
}
]
}
}}
Clients MAY submit several combinations of interests
input:
// sample template object with list object and type property
*** REQUEST ***
POST /my-collection/ HTTP/1.1
Host: www.example.org
Content-Type: application/vnd.collection.next+json
{
"template": {
"data" : [
{"name": "interests", "value": "sports"},
{"name": "interests", "value": "music"}
]
}
}
OR
// sample template object with list object and type property
*** REQUEST ***
POST ...
{
"template": {
"data" : [
{"name": "interests", "value": "sports"}
]
}
}
OR
// sample template object with list object and type property
*** REQUEST ***
POST ...
{
"template": {
"data" : [
{"name": "interests", "value": "music"}
]
}
}
2.2. status
The status object is an OPTIONAL child property of the collection object. There MUST NOT be more than one status object in a document. It is a top-level document property
The status object MAY contain any of two possible properties: code (OPTIONAL), message (REQUIRED).
The status object's purpose is to fulfill requirements defined by HTTP 202 Accepted status code.
// sample payment data submission request
***REQUEST***
POST /payments HTTP/1.1
Host: service.com
Content-Type: application/vnd.collection.next+json
Content-Length: ...
{
"template": {
"data": [
{"name": "name", "John Doe"},
{"name": "email", "value": "john@doe.com"},
{"name": "creditcard", "value": 41111111111111},
{"name": "cvv2", "value": 123}
]
}
}
// sample payment data submission response
***RESPONSE***
HTTP/1.1 202 Accepted
Location: http://service.com/payments/8888
Content-Type: application/vnd.collection.next+json
Content-Length: ...
{
"collection": {
"version": 1.0
"href": "http://service.com/payments/8888",
"status": {
"code": "inprogress",
"message": "Payment is being processed"
}
}
}
2.3. method
The method object represents list of all supported HTTP methods which can be potentially used for manipulating documents. This is an OPTIONAL object and is a child property of of the template object.
The method object SHOULD have an options array.
// sample method object
{
"template": {
"method": {
"options": [ARRAY]
},
"data": [ARRAY]
}
}
If the method object presents, it's
options array SHOULD only contain any of
HTTP POST
, PUT
and PATCH
methods which SHOULD be used by clients for manipulating particular collection
items.
// sample method object, only POST method is allowed
{
"template": {
"method": {
"options": [
{"value": "POST", "prompt": "Create Entry"}
]
},
"data": [ARRAY]
}
}
OR
// sample method object, PUT and PATCH methods are allowed
{
"template": {
"method": {
"options": [
{"value": "PUT", "prompt": "Replace Entry"}, // replace entire resource
{"value": "PATCH", "prompt": "Modify Entry"} // or modify resource partially
]
},
"data": [ARRAY]
}
}
OR
// sample method object, only POST method is allowed
{
"template": {
"method": {
"options": [
{"value": "PATCH", "prompt": "Modify Entry"} // only partial updates of resource is supported
]
},
"data": [ARRAY]
}
}
Support of HTTP's GET
and HEAD
methods SHOULD be always assumed by clients.
2.4. enctype
The enctype object represents a list of all supported content types other than
application/vnd.collection.next+json
which potentially MAY be accepted by server for write requests.
This is an OPTIONAL object and is a child property of of the
template object.
The enctype object SHOULD have an options array.
// sample method object
{
"template": {
"method": {
"options": [ARRAY]
},
"enctype": {
"options": [
{"value": "application/x-www-form-urlencoded", "prompt": ""}
]
},
"data": [ARRAY]
}
}
Translation rules to other types MUST be defined by service implementors.
Current specification only defines translation rules for application/x-www-form-urlencoded
content type(see. Translating to application/x-www-form-urlencoded).
Despite the provided list of other supported content types, support for application/vnd.collection.next+json
format MUST be always assumed by clients and services.
3. Arrays
An array is an ordered sequence of zero or more values.
Extension defines set of new arrays. These are: options and messages.
3.1. options
The options array MAY be a child property of the list and method objects.
The options array SHOULD contain one or more anonymous objects. Each object MAY have any of two possible properties: value (REQUIRED) and prompt (OPTIONAL).
// sample options array
{
"template": {
"data": [
{"name": STRING, "value": 0, "prompt": STRING, "list:" {
"options": [
{"value": VALUE, "prompt": STRING},
...
{"value": VALUE}
]
}}
]
}
}
3.2. messages
The messages array is a child property of the error object property.
The messages array SHOULD contain one or more anonymous objects. Each object MAY have any of three possible properties: code (OPTIONAL), name (OPTIONAL) and message (REQUIRED).
// sample messages array
"error": {
"code": STRING,
"messages": [
{
"code": STRING,
"name": STRING,
"message": STRING
}
...
{
"name": STRING,
"message": STRING
}
...
{
"message": STRING
}
]
}
4. Properties
Properties represent individual name/value pairs for objects within Collection+JSON documents.
Extension introduces several extra properties, these are: the type property which meaning depends on the enclosing object, the multiple, the default, and the required.
4.1. type
The type is an OPTIONAL property and MAY be a child property of the links array elements and the data array elements when part of the template and queries array.
It SHOULD be a STRING data type.
4.1.1. Using type property with links array elements
When used with
the links
array elements the value SHOULD be a standard MIME type. If the
type property does not appear on a
links
array element, it should be assumed to be set to application/vnd.collection.next+json
.
// sample links array
{
"version": "1.0",
"href": URI,
"items": [
{
"href": URI,
"data": [ARRAY],
"links": [
{"href": URI, "rel": STRING, "prompt": STRING, "type": "image/png"},
{"href": URI, "rel": STRING, "prompt": STRING, "type": "image/jpeg"},
{"href": URI, "rel": STRING, "prompt": STRING, "type": "audio/mpeg3"},
{"href": URI, "rel": STRING, "prompt": STRING, "type": "application/rss+xml"},
...
{"href": URI, "rel": STRING, "prompt": STRING}
]
}
]
}
4.1.2. Using type property with data array elements
By introducing possibility to explicitly indicate desired data types for the input objects, extension addresses several important issues:
-
Strengthen semantics of input objects.
-
By relying on commonly recognized types protect clients from implementing input processing logic relevant to only particular service format.
-
Possibility to define agreed validation strategies on both - service and client sides.
-
Reduce communication between service and client by making data array elements more self contained and self explanatory.
-
Improve interoperability between heterogenous platforms(i.e. statically typed vs dynamically typed languages) without introducing additional complexity.
-
By reducing need to describe types of the input objects somewhere else, minimize hardcoding in service clients.
-
Improve rendering options in client applications. Client applications MAY determine rendering strategy by relying on the value of the type property and use most appropriate input controls in order to increase quality of interaction between application and user.
Table below describes supported HTML5 input types which service implementors and clients MAY user in order to describe and determine meaning of the input objects:
Type | State(HTML5) | Data Type(HTML5) | Data Type(Collection+JSON) |
---|---|---|---|
number |
Number | A numerical value | NUMBER |
email |
An e-mail address | STRING | |
url |
URL | An absolute URL | STRING |
date |
Date | A date (year, month, day) with no time zone | STRING |
datetime |
Date and Time | A date and time (year, month, day, hour, minute, second, fraction of a second)
with the time zone set to UTC |
STRING |
month |
Month | A date consisting of a year and a month with no time zone | STRING |
tel |
Telephone | Text with no line breaks | STRING |
Below is the example data array using HTTP5 type attribute values for specifying input object type:
// sample usage of type property in the data array
{
"template": {
"data": [
{"name": STRING, "type": "number", "prompt": STRING}, // NUMBER type
{"name": STRING, "type": "email", "prompt": STRING}, // email STRING type
{"name": STRING, "type": "url", "prompt": STRING}, // url STRING type
{"name": STRING, "type": "date", "prompt": STRING}, // date STRING type
{"name": STRING, "type": "datetime", "prompt": STRING}, // datetime STRING type
{"name": STRING, "type": "month", "prompt": STRING}, // month STRING type
{"name": STRING, "type": "tel", "prompt": STRING} // telephone STRING type
]
}
}
Additionally extension specification defines two explicit data types integer
and boolean
. Table below summarizes both of these types:
Type | Description | Data Type(Collection+JSON) |
---|---|---|
integer |
An integer value. When the type is specified any signed integer value SHOULD be used as a value of the value property. | NUMBER |
boolean |
A boolean value. When the type is specified any of two true or false literal values MUST be used as a value of
the value property. |
VALUE |
// sample default value usage in the data array
{
"template": {
"data": [
{"name": STRING, "prompt": STRING}, // no type specified, any VALUE is legal
{"name": STRING, "value": 0, "prompt": STRING, "type": "integer"}, // integer type
{"name": STRING, "value": false, "prompt": STRING, "type": "boolean"} // boolean type
]
}
}
4.2. multiple
The multiple is an OPTIONAL property and MAY be a child property of the list object.
It SHOULD be a boolean
type and MAY only be specified to boolean true
or false
.
// sample usage of multiple property
{
"queries": [
{
...
"data" : [
{
"name": "gender",
"list": {
"multiple": true,
"options": [
{"value": "female", "prompt": "Female"},
{"value": "male", "prompt": "Male"}
]
}
}
]
}
]
}
4.3. default
The default is an OPTIONAL property and MAY be a child property of the list object.
It's value SHOULD be specified from one of the options array elements value property.
// sample usage of default property
{
"queries": [
{
...
"data" : [
{
"name": "gender",
"list": {
"multiple": true,
"default": "female", // indicates default value
"options": [
{"value": "female", "prompt": "Female"},
{"value": "male", "prompt": "Male"}
]
}
}
]
}
]
}
4.3. required
The required is an OPTIONAL property and MAY be a child property of the data array elements.
It SHOULD be a boolean
type and MAY only be specified to boolean true
or false
.
// sample usage of the required property in the data array
{
"template": {
"data": [
{"name": STRING, "type": "number", "prompt": STRING, "required": true},
{"name": STRING, "type": "email", "prompt": STRING, "required": true},
{"name": STRING, "type": "url", "prompt": STRING, "required": false},
{"name": STRING, "type": "date", "prompt": STRING},
{"name": STRING, "type": "datetime", "prompt": STRING, "required": true},
{"name": STRING, "type": "month", "prompt": STRING},
{"name": STRING, "type": "tel", "prompt": STRING}
]
}
}
5. Link Relations
Link relations can be used to annotate links array elements.
Specification defines one new link relation value.
5.1. form
The target IRI points to a resource that is a representation of a valid write form(create or edit) for the data represented by the context IRI.
This is a generic relation type and doesn't necessarily refer to the template object.
When included in a resource which represents a collection, the form link relation identifies a target resource that represents the form for adding a new member to the context collection.
// sample form relation use
GET /news HTTP/1.1
Host: example.org
Accept: application/vnd.collection.next+json
{
"collection": {
"version": 1.0
"href": URI,
"items": [
{OBJECT},
{OBJECT},
...
{OBJECT}
],
"links": [
{
"rel": "form",
"href": URI,
"prompt": "Add new item..."
}
]
}
}
In the example above rel="form"
indicates that dereferencing of the URI SHOULD return representation of a valid create form.
In this particular case the template object.
When included in a resource which represents a member of a collection, the form link relation identifies a target resource that represents a pre-populated form for editing the context resource.
When the form
relation value is used inside the item object,
dereferencing of the URI SHOULD return the pre-populated valid template object.
// sample form relation use
GET /news/12345 HTTP/1.1
Host: example.org
Accept: application/vnd.collection.next+json
{
"collection": {
"version": 1.0
"href": "http://example.org/news",
"items": [
{
"href": "http://example/org/news/12345",
"data": [ARRAY],
"links": [
{
"rel": "form",
"href": "http://example/org/news/12345/edit-form",
"prompt": "Edit item..."
}
]
},
{OBJECT},
...
{OBJECT}
],
}
}
As far as the form
relation value is intentionally generic service implementors MAY support various types of forms.
Different types of forms SHOULD be indicated by the type property value in links array elements.
// sample form relation use
GET /news HTTP/1.1
Host: example.org
Accept: application/vnd.collection.next+json
{
"collection": {
"version": 1.0
"href": URI,
"items": [ARRAY],
"links": [
{
"rel": "form",
"href": URI,
"type": "application/xhtml+xml",
"prompt": "Add new item..."
}
]
}
}
6. Translating to application/x-www-form-urlencoded
One of the goals of this specification is to define clear ways for translating content for update requests from application/vnd.collection.next+json
to other formats.
Current specification defines translation rules only for application/vnd.collection.next+json
to application/x-www-form-urlencoded
.
Translation rules to other formats MUST be defined by service implementors.
Supported content types other than application/vnd.collection.next+json
SHOULD be provided through enctype object.
Translation rules to to application/x-www-form-urlencoded
are as follows:
-
null
values MUST be converted to empty strings""
. -
boolean
values MUST be converted tointeger
0
and1
correspondingly. -
Encoding of name/value pairs MUST conform to RFC3986 and MUST be properly implemented by clients.
Below is the example implemented in pure JavaScript for translating data array to application/x-www-form-urlencoded
format.
/** * encodeURIComponent() function is not 100% compatible with * RFC3986 http://www.faqs.org/rfcs/rfc3986.html */ function encodeRFC3986(value) { return encodeURIComponent(value) . replace( /!/g, "%21") . replace( / \* /g, "%2A") . replace( / \( /g, "%28") . replace( / \) /g, "%29") . replace( /'/g, "%27"); } function translateToFormUrlEncoded(data) { var buffer = []; for ( var i = 0; i < data.length; i++) { var input = data[i]; var name = input.name; var value = input.value; if (value === null) { // convert null value to empty string value = ''; } else if ( typeof value === "boolean") { // convert boolean value to integer 0 or 1 value = Number(value); } buffer. push( encodeRFC3986(name) + "=" + encodeRFC3986(value)); } return buffer. join( "&"); } var data = [ { "name": "first-name", "value": "John"}, { "name": "last-name", "value": "Doe"}, { "name": "email", "value": "john@doe.com"}, { "name": "website", "value": "http://john.doe.com"}, { "name": "age", "value": 37}, { "name": "interests", "value": "music"}, { "name": "interests", "value": "sports"}, { "name": "interests", "value": "cars"}, { "name": "subscribe", "value": false} ]; // convert data array to application/x-www-form-urlencoded var postData = translateToFormUrlEncoded(data);
// encoded contents of resulting postData variable first-name=John&last-name=Doe&email=john%40doe.com&website=http%3A%2F%2Fjohn.doe.com&age=37&interests=music&interests=sports&interests=cars&subscribe=0
7. Acknowledgements
Special thanks to Mike Amundsen for insightful advices and permissions to use Collections+JSON specification as a reference material.