Introduction

This proposal is a work in progress and aims to address the perceived problems with various REST and JSON style guides with the goal of providing the following:

  • Ease of data access. The client should never need to iterate through lists of objects on single resource requests. Data should be available as properties.
  • Metadata specific to the request but separate from the resource data.
  • Bundling of data in the response. Multiple resources and resource lists SHOULD be supported.
  • Name-safe. Naming conflicts and reserved properties MUST be avoided.
  • Normalized responses. Single objects MUST have the same structure as lists of resources, so client code can accept resources regardless of their origin. However, single resource requests MAY be more detailed.
  • Type independent. Clients MUST NOT need to check the type of a property. The use of data and dataList reflects the decision to use different properties for different types.
  • Responses and requests formats MUST match. Requests and responses MUST use the data: {resource:} or dataList: {resource:} formats.

Terminology

The terms object, member, array, number, name, and string in this document are to be interpreted as described in RFC 7159.

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.

Data Format

Server request and response bodies, if present, should contain JSON.

Auto-discovery

A server MUST implement a options call. The request method SHOULD allow this request as GET or OPTIONS. The uri SHOULD be /options.

{
    "status": 200,
    "options": {
        "myResource": { 
            "href": "/my-resource",
            "controllers": {
                "update": { 
                    "uri": "/update",
                    "method": "POST",
                },
                "list": { 
                    "uri": "/list",
                    "method": "GET",
                    "multi": true
                }
            }
        }
    }
}

Using the above example, a client should be able to build request urls fairly easily. For example, to call the controller update on myResource with ID of 7, one would call: /my-resource/7/update. To call the list multi controller on myResource one would call: /my-resource/list.

Requests

Resource POST/PUT

A post to a single resource MUST use the data property.

{
    "data": {
        "myResource": {
            "myField": "Some value",
            "myOtherField": "Foo"
        }
    }
}

Resource list POST/PUT

POSTing to multiples of the same resource (such as a bulk create operation) MUST use the dataList property.

{ 
    "dataList": {
        "myResource": [
            {"myField": "Some value", "myOtherField": "Some other value" },
            {"myField": "Foo", "myOtherField": "bar" }
        ]
    }
}

A server MAY support multiple dataList objects.

{
    "dataList": {
        "author": [
            {"name":"Bill", "id":1},
            {"name":"Sally", "id":2}
        ],
        "articles": [
            {"title":"Bill's Article", "authorId":1},
            {"title":"Sally's Article", "aithorId":2}
        ]
    }
}

Responses

Resource response

More than one resource MAY be returned, but only one of each type of resource.

Resource responses SHOULD contain meta and data objects. Meta data can be updated in the client's scope on each request. This is the reason an options request does NOT use meta, since options should only need to be retrieved once.

{
    "status": 200,
    "error": "A server-level error, such as a caught but unknown exception",
    "data": { 
        "myResource": { 
            "myField": "foo",
            "myOtherField": "bar"
        }
    },
    "meta": { 
        "myResource": {
            "errors": ["List of Object-level errors"],
            "fields": {
                "myField": { 
                    "error": "Field-specific error"
                }
            }
        },
    }
}

Members

  • meta - OPTIONAL. A meta object describes request messaging.
  • data - REQUIRED. This is the data returned from a single resource GET request. However, data is OPTIONAL for POST, PUT, and DELTE requests.

Access examples

  • Field value: data.myResource.myField
  • Field metadata: meta.myResource.fields.myField

Resource list response

The server MUST return lists of data using the dataList property instead of data. This is because a client MUST NOT be required to type-check.

{
    "status": 200,
    "error": "A server-level error, such as a caught but unknown exception",
    "dataList": { 
        "myResource": [
            { "myField": "foo", "myOtherField": "bar" },
            { "myField": "baz", "myOtherField": "quux" }
        ]
    },
    "meta": { 
        "myResource": {
            "errors": ["List of Object-level errors"],
            "fields": {
                "myField": { 
                    "error": "Field-specific error"
                }
            }
        }
    }
}

Members

  • meta - OPTIONAL Same format as single resource requests.
  • dataList - REQUIRED. Contains one or more properties with the name of a resource, and the value of each property is a list of resource objects.

Access examples

  • Field value: dataList.myResource[1].myField
  • Field metadata: meta.myResource.fields.myField (The same as with other requests)