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.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 to integer 0 and 1 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.

8. References