JSON Resources: A proposal for a RESTful JSON protocol

730 views
Skip to first unread message

Kris Zyp

unread,
Sep 5, 2008, 11:33:16 AM9/5/08
to restfu...@googlegroups.com
Below is my proposal for a RESTful JSON protocol, called JSON resources. This proposal is focused on defining the use of REST architecture for integration with JSON documents, and intends to leverage and build on existing standards, and on existing implementations (and my experience working on them). However, this proposal is not a reverse-engineer or documentation of any existing implementation. Where possible, this proposal uses implementation tested or existing standards based techniques; there are a number of mechanisms in here that are somewhat new, partly due to desires expressed by this group, or by applications of standards that simply have not yet been implemented due to lack of demand so far. This proposal is admittedly quite rough, but hopefully it can serve to put forth some ideas for a RESTful JSON protocol.
 
I don't believe this proposal is mutually exclusive with John Cowan's proposal for JSON Web Collections. The JSON resources proposal is primarily concerned with semantics of RESTful communication and interaction with JSON data, and generally does not impose any format/structure on the JSON data, however I did include a section on defining a structure for collections that uses a top-level array that is partly based on Cowan's proposal, although this is rather peripheral to main focus of the proposal. Even beyond top-level objects, JSON Web Collections may also be useful as an additional content type as a JSON structure for inclusion of per-resource metadata. This may have value with metadata intensive application, and I think it should work properly with the JSON resources proposal.
 
 

JSON Resources Proposal

Abstract

The JSON resources proposal defines how to interoperably use JSON on a REST architecture. JSON resources describes how to meaningfully apply the specifications defined in the HTTP protocol (http://www.ietf.org/rfc/rfc2616.txt) to JSON data, and integrate information from JSON resources into high level interaction. As much as possible, this proposal follows the HTTP specification.

JSON resources does not specify a JSON format, any valid JSON structure can be used with JSON resources. JSON resources does recommend a structure for hyper-referencing objects, but this structure can still be used with any JSON format, and it is not required. The specification assumes the use of the HTTP protocol for RESTful interaction because of it’s ubiquity and position as the reference implementation for REST. JSON resources can be used with any REST architectures, but alternate REST architecture bear the responsibility for defining the resource metadata and methods in their own equivalent terms.

Resource Locator Determination

A central function of the JSON resources specification is determining the locator path for JSON resources. When a resource is retrieved through a request, the top-level resource that is returned in the response has an implicit locator, the same locator that was used to retrieve the resource. An alternate canonical locator can be provided by the server with the "Location" header as defined in the HTTP specification.

JSON is hierarchical in nature. A top level JSON entity (object or array) may have objects that can be treated as resources as themselves. In order for these sub-entities to be properly treated as resources, a client must be able to determine the resource’s locator path (URL). An object’s URL is determined from the object’s locator property, treated as a relative URL. To calculate an object’s URL, the URL used to retrieve the JSON document is the base URL and the value of the locator property is the relative URL. Then, the absolute URL can be computed based on RFC 1808’s specification (http://www.ietf.org/rfc/rfc1808.txt).

A server can declare which property is the locator property for objects in an JSON document with a MIME parameter (MIME parameters are defined in http://tools.ietf.org/html/rfc2045#section-5). Alternate JSON sub-content types (like application/collections+json) may utilize a predefined JSON structure which indicates the locator property. When a MIME parameter is used to define the locator property. The MIME parameter name should be "locator" and the value should be the name of the locator property. For example if the content type of the resource was "application/json" (alternate subtypes are allowed), then the locator property can be declared by suffixing the content type, and the following JSON representation could be sent. If the a request was made to http://site.com/Person/, then the following response could be returned:

Content-Type: application/json;locator=my_id
[
 {"my_id":"1","name":"John Doe"},
 {"my_id":"2","name":"Jane Doe"}
]

This resource representation would indicate that two subresources have been included. The first subresource has locator (computed by relative URL) of http://site.com/Person/1 and is represented by:

{"my_id":"1","name":"John Doe"}

If a request is made to http://site.com/Person/1 with the same headers as the initial response, the server should respond with the representation shown above. If the client wishes to modify the resource it may request the modification by sending a PUT method and the representation of the resource with modifications.

PUT /Person/1

{"my_id":"1","name":"Jim Doe"}

If the server permits the operation, the resource should be modified to match the provided representation. New properties that were not in the old version should be added, modified properties should be updated, and properties not listed in the old version should be deleted.

The client may request the deletion of the resource with the DELETE method:

DELETE /Person/1

Resource Creation

New resources may be created by using a POST method with a collection resource, or a PUT method with an client defined location. A collection resource is a resource that returns an array of JSON values that represent subresources. To attempt to create a new resource in a collection, a client can make a POST request to the URL for the collection resource with a JSON value indicating the desired properties or values of the resource to be created. For example:

POST /Person/

{"name":"Josh Doe"}

This indicates that the client requests a new object be created with a "name" property with the value of "Josh Doe". If successful, the server respond with a response with a status of 201 Created. The response must also include a "Location" header that indicates the location of the newly created resource. For example:

Location: /Person/3

If the server does not support creation of resources in this manner, or the operation was unauthorized, the server should respond with the appropriate HTTP response status.

A new resource may alternately be created with the PUT method. With the approach, the client provides the location for which it desires the resource to be accessible from in the future. The desired resource representation should still be included as with a POST method creation except that the client should include the appropriate locator property corresponding to the new resource’s location. For example:

PUT /Person/josh

{"my_id":"josh","name":"Josh Doe"}

If the operation is successful, the server should respond with a 201 status. The server may include a "Location" header indicating where the resource will be accessible from in the future, however this is not necessary if the client’s defined location is acceptable to the server.

Hyper References

A JSON resource may utilize JSON referencing for linking to other resources. A property may utilize a reference to indicate that it’s value can be determined by resolving the reference. An array item may also use a reference to indicate it’s target value. A JSON reference is a JSON object with a property named "$ref", and a value indicating the location of the resource to be used as the value. The value can be resolved to a URL by relative URL computation in the same manner as the locator property. A client can use the computed URL to retrieve the resource to resolve the reference. For example, if a JSON resource retrieved from http://site.com/Person/1 was represented:

{"my_id":"1","name":"John Doe","spouse":{"$ref":"2"}}

This would indicate that the "spouse" property’s value is the JSON resource located at http://site.com/Person/2. If both subresources http://site.com/Person/1 and http://site.com/Person/2 were both provided within a single collection:

[
 {"my_id":"1","name":"John Doe","spouse":{"$ref":"2"},
 {"my_id":"2","name":"Jane Doe","spouse":{"$ref":"1"}
]

The client would not need to make any additional requests, but would know that the first object’s spouse property’s referent was the second object and vice versa.

Property Path Based Referencing

References are not limited to self-identified, URL locatable JSON resources. JSON values embedded within the data structures of JSON resources can be referenced by using path-based references. These references include a property path that indicates where the JSON value can be found. A property path is composed of property segments that each refer to the property name to be used to progressively locate a JSON value. A full path-based reference may optionally start with location path (relative URI as with a standard JSON reference) followed by an optional #, followed by path segments. A path segment may be a . followed by a property name,a quoted string enclosed in brackets, or a number enclosed in a bracket. If the reference starts with # instead of object location, the current JSON resource should be considered the starting point for the property reference. For example:

GET /Person/
[
 {"my_id":"1","name":"John Doe","spouse":{"$ref":"2"},
       children:[{"my_id":"3","name":"Jill Doe"}]},
 {"my_id":"2","name":"Jane Doe","spouse":{"$ref":"1"}
       children:{"$ref":"1#.children"}}
]

In this example, both "John Doe" and "Jane Doe" refer to the same "children" JSON array. Another example:

{"my_id":"1","foo":[{"bar":3},{"$ref":"#.foo[0]"}]}

In this example, the resource indicates that both the first and second entry in the array in the "foo" property, should be the same object (the object {"bar":3}). The grammar for a JSON reference (building on the grammar defined in RFC 2616):

json-reference = "{" <"> "$ref" <"> ":" <"> [relativeURI | absoluteURI] ["#"] *property-segment <"> "}"
property-segment = ("." token) | ("[" 1*DIGIT "]") | ("[" single-quoted-string "]")
single-quoted-string = "'" *(<any TEXT except "'"> | single-quoted-pair) "'"
single-quoted-pair = "\" CHAR

Partial Loading

A reference object is not limited to only have the "$ref" property. A reference object may include any properties from the target resource object. A reference object can include any property desired from the target resource object. Any properties included in a reference object should have the same value as the target resource object, with the exception that the properties that have a string value may use a truncation of the true value. Reference objects with partial sets of properties can be useful for efficient transfer of relevant information, while allowing clients to request more detailed information as needed. For example, a collection could include references

[
 {"$ref":"1","name":"John Doe"},
 {"$ref":"2","name":"Jane Doe"}
]

A client could then provide a list of people’s names. A request for more detailed information could be made by making a request to the actual target location , and the target resource object would include a full set of properties (perhaps age, spouse, etc).

A client can request that the objects that are returned from the server only include certain properties using a Range header with "properties" range units. The "properties" range unit defines a set of properties with a comma delimited set of property names as tokens or quoted strings. For example, to request a collection of objects where each object only includes the "name" property:

GET /Person/ HTTP/1.1
Range: properties=name

If the server supports the "properties" range unit, the server should return a response like the example above where each object is a reference object with the properties specified in the Range header.

Permission Indication

A server may indicate the acceptable forms of modification to a given JSON resource by including an "Allow" header. The Allow header value should be a list of allowed methods. PUT indicates that a resource can be updated. DELETE indicates that the resource may be deleted. POST may be included with a collection resource to indicate new resources may be created as a subresources of the collection resource.

When a collection resource is requested, a "X-Sub-Allow" header may also be included that indicates the allowable operations on the sub-resources:

For example, if a server responded to the request for /Person/ with headers:

Allow: GET, HEAD, POST
X-Sub-Allow: GET, HEAD, PUT

This would indicate new resources may be created with the POST method, and sub resources can be updated, but not deleted.

Note that a server should be prepared to handle any method (and possibly reject), as a client may not respect the Allow header.

Permission Setting

When creating a JSON resource with a PUT or POST method, or modifying a JSON resource with a PUT method, the client may wish to indicate the desired permission level of the resource. The client may do this by including an Allow header in the request. The Allow header should indicate permission by including a list of allowed methods. Generally the permission level indicated should be the permission for the general public (someone with special permissions) to access the resource. GET indicates readable, HEAD indicates meta-data is accessible, PUT indicates updateable, DELETE indicates it is deletable, and POST may be used if you have created a new collection resource that can accept new resources within it. For example, creating a new resource that is intended to be publicly readonly could be done with a request:

POST /Person/
Allow: HEAD, GET
...

Paging

A subset of a collection (a JSON resource that is represented as an array) may be requested by using a Range header with the "items" range unit. A Range header can specify the set of array items to be returned by index. The Range header follows the same rules as HTTP RFC 2616 specifies for byte range units, except applied to collection indices.

The returned entity from a Range should be a textual section of the entire JSON array. Consequently, the entity should start with "[" only if the first item in the array is included. It should end with "]" only if the last item is included, otherwise it should end with a ",". This allows Range responses to be properly concatenated by non-JSON aware proxy servers.

The response should also include a Content-Range header indicating the items returned and the total count using the format defined in RFC 2616. For example:

GET /Person/ HTTP/1.1
Range: items=0-1
response:
Content-Range: items 0-1/33
[{"$ref":"1","name":"John Doe"},
 {"$ref":"2","name":"Jane Doe"},

Servers that can respond to Range requests with the "items" range unit should indicate this capability by including the Accept-Ranges header on responses:

Accept-Ranges: items

Partial Object Updates

Normally, JSON resouces are updated in whole with a PUT operation. However, a PUT operation can update a subset of the properties of a JSON object using a partial update. To indicate a partial update, the client includes a Content-Range header with a properties range unit. The properties that should be affected by the update should be comma delimited after the "properties" range unit declaration. Properties may be tokens or quoted strings.

PUT /Person/2
Content-Range: properties name,"current age"
{"name":"Kristopher",
 "current age",32}

If a property is listed in the Content-Range header, but is omitted from the JSON object representation in the entity, this indicates that this property should be deleted.

A server that can handle partial object updates using the "properties" range unit may indicate this capability with the Accept-Ranges header. For example to indicate support for "items" and "properties" range units:

Accept-Ranges: items, properties

Table and Schema Discovery

The set of available JSON collections or tables can be advertising using Service Method Description (SMD) (http://groups.google.com/group/json-schema/web/service-mapping-description-proposal). The SMD may include schema information that defines the structure of the objects in the table as defined in JSON Schema (http://json-schema.org). It is recommended that an SMD that lists the available tables should be available at /SMD. The SMD should define a transport of "REST" and a envelope of "PATH". For example:

{
"transport":"REST",
"envelope":"PATH",
"services":{
   "Person" :{
      "type":"object",
      "properties":{
          "name":{"type":"string"},
          "age":{"type":"integer"}
       }
   }
 }
}

An SMD may be used to describe many other services besides the REST services described in this proposal.

If a table location is already known, the contents of the table should be accessible by accessing the table location with a trailing "/". A schema should be directly accessible by accessing the table location without a trailing "/".  To retrieve the schema for the "Person" table:

GET /Person

response:

{
      "type":"object",
      "properties":{
          "name":{"type":"string"},
          "age":{"type":"integer"}
       }
   }

Doing GET /Person/ should return the contents of the table. A server may choose to refuse this request if lack of query restrictions would cause an excessively large list of data to be returned, in which case the server should return a 416 Requested Range Not Satisfiable.

Non-HTTP REST

JSON resources is designed to leverage the existing infrastructure and mechanisms available in the HTTP protocol. However, JSON resources may also be used in environments where HTTP is absent or not accessible, such as cross-frame messaging in a browser, JSONP, direct TCP/IP communication, or Web sockets based communication. In these situations, a JSON based REST format may be utilized:

REST Request Message

JSON Format Property Definition
target This defines the target path of the resource that was requested
method This defines the method/verb to be executed. This can be get, put, post, delete , or any other available methods. This property is optional (it may be omitted if the client only wants to make a subscription without requesting any data).
content This property provides the data to be applied to the target path. This is the new object data for puts and posts
params This is an optional property that when present should be an array that provides additional arguments for the execution of the method.
id This is an optional identifier that can be used for correlating requests with responses over transports that do not have specific request-response mechanism (like cross-frame messaging or TCP/IP).

REST Response Message

A REST response message should be returned for all REST requests.

JSON Format Property Definition
result This property provides the entity/data returned from the request.
type The type of the JSON data
locator The locator property that is used within the JSON data.
error If an error occurred in handling the request, the error information can be included in this optional property.
id If the request had an id property, the response should include the same id to correlate the response to the request.
source This optional property indicates the resource that was requested. If no id was provided by the request message, and the underlying transport does not make request/response correlation, this can be used to understand what resource was delivered.

This message format would be defined as "application/rest+json".

Another related format type may define additional resource metadata for item in the collection (possibly "application/collection+json").

Rational

REST is an architectural approach that should impose no (or minimal) constraints on the actual resource content. JSON Resources can be used with any existing JSON data structure. Integrating into and leveraging REST (via hyperlinking) should be feasible for JSON documents without significant alterations to the data.

 
 

Ernest Prabhakar

unread,
Sep 5, 2008, 5:50:01 PM9/5/08
to restfu...@googlegroups.com
Hi Kris,

On Sep 5, 2008, at 8:33 AM, Kris Zyp wrote:
> I don't believe this proposal is mutually exclusive with John
> Cowan's proposal for JSON Web Collections. The JSON resources
> proposal is primarily concerned with semantics of RESTful
> communication and interaction with JSON data, and generally does not
> impose any format/structure on the JSON data, however I did include
> a section on defining a structure for collections that uses a top-
> level array that is partly based on Cowan's proposal, although this
> is rather peripheral to main focus of the proposal. Even beyond top-
> level objects, JSON Web Collections may also be useful as an
> additional content type as a JSON structure for inclusion of per-
> resource metadata. This may have value with metadata intensive
> application, and I think it should work properly with the JSON
> resources proposal.

Very impressive! I'm not sure I grok it all, but I think you covered
all the bases. Now we need someone to start building pieces to see
what does and doesn't work for *their* use cases...

-enp


Jeni Tennison

unread,
Sep 11, 2008, 3:48:04 PM9/11/08
to restfu...@googlegroups.com
Kris,

On 5 Sep 2008, at 16:33, Kris Zyp wrote:
> Below is my proposal for a RESTful JSON protocol, called JSON
> resources.

This is a really useful proposal, especially given that it's based on
so much existing practice. I have several questions about it, some of
which I'll put in separate emails so that they're easier to track.

My first group of questions is about sub-resources that are collection
resources. Say I have:

Location: /user/
Content-Type: application/json; locator=id

[{"id": "jdoe",
"name": "John Doe",
"accounts": [{"site": "google.com",
"username": "john.doe"},
{"site": "flickr.com",
"username": "johnny"}]}
...]

Here, the accounts property holds a collection resource (an array of
objects). Let's say that the canonical location of each of those
"account" resources is of the form:

/user/{user.id}/account/{account.site}

Does the "locator property" specified in the Content-Type carry
through into the sub-resources or not? Do I have to do:

[{"id": "jdoe",
"name": "John Doe",
"accounts": [{"id": "jdoe/account/google.com",
"site": "google.com",
"username": "john.doe"},
{"id": "jdoe/account/flickr.com",
"site": "flickr.com",
"username": "johnny"}]}]

to indicate the URI of each of those resources? Or am I expected to
use "$ref" here:

[{"id": "jdoe",
"name": "John Doe",
"accounts": [{"$ref": "jdoe/account/google.com",
"site": "google.com",
"username": "john.doe"},
{"$ref": "jdoe/account/flickr.com",
"site": "flickr.com",
"username": "johnny"}]}]

Note that the id/$ref that I've specified on each of the accounts here
is relative to the location of the (user) collection resource, as
specified in the proposal. The value of the id/$ref property would
therefore have to change if I retrieved the accounts directly or in
another collection. For example:

Location: /user/jdoe/account/
Content-Type: application/json; location=id

[{"id": "google.com",
"site": "google.com",
"username": "john.doe"},
{"id": "flickr.com",
"site": "flickr.com",
"username": "johnny"}]

It seems that under this proposal, I can either always provide an
absolute URI, or be prepared to change the JSON representation of a
resource depending on the collection that it's being requested as part
of. Is that correct? I wonder if it would be helpful if URIs within a
resource were resolved relative to the URI of the resource itself,
instead. So I would do:

[{"id": "jdoe",
"name": "John Doe",
"accounts": [{"id": "google.com",
"site": "google.com",
"username": "john.doe"},
{"id": "flickr.com",
"site": "flickr.com",
"username": "johnny"}]}]

(Though even then it's annoying having to replicate the value of the
"site" property into the "id".)

Anyway, this leads nicely to the question of how an application could
know that the array held in the "accounts" property is a collection
resource that is POSTable to at /user/jdoe/account/. Do I have to do:

Location: /user/
Content-Type: application/json; locator=id

[{"id": "jdoe",
"name": "John Doe",
"accounts": {"$ref": "jdoe/account/"}}
...]

and have applications put in a separate request to "/user/jdoe/
account/" in order to get back the collection of accounts:

Location: /user/jdoe/account/
Content-Type: application/json; locator=site

[{"site": "google.com",
"username": "john.doe"},
{"site": "flickr.com",
"username": "johnny"}]

In this case, there's no way to tell from the /user/ collection that
the accounts property holds another collection resource rather than a
normal resource (because the "accounts" property no longer holds an
array). Or is the presence of the '/' at the end of the URI sufficient
to indicate this?

I can certainly see the attraction of having collections be simple
arrays, but it seems that as you get into collection sub-resources you
really need somewhere to indicate locations, and perhaps other
metadata, about the collection. That doesn't necessarily mean the
collections can't be arrays, just that there needs to be some extra
support for it. For example you might introduce a reserved
"$collections" property to give the URI of the collection resources
equivalent to those properties that hold arrays:

[{"id": "jdoe",
"name": "John Doe",
"accounts": [{"site": "google.com",
"username": "john.doe"},
{"site": "flickr.com",
"username": "johnny"}],
"$collections": {"accounts": "account/"}}
...]

or you might have a separate description document that provided both
the schema and the URI bindings for such properties.

Have I missed the obvious way of doing this?

Thanks,

Jeni
--
Jeni Tennison
http://www.jenitennison.com

rektide

unread,
Sep 11, 2008, 4:54:30 PM9/11/08
to restful-json
Good stuff.

If I wish to hyper-reference a /posts collection from the /people
collection, I have to {"$ref": "../posts/1"} ? Is that right? Why
are absolute uri's not permitted? We'll see this problem flare to far
greater proportions shortly.

The property path reference threw my head for a loop. I would like to
see more examples of valid path references. Your BNF notation
introduces absolute URI's which are not references and there are no
examples for.

The phrase "If the reference starts with # instead of object location,
the current JSON resource should be considered the starting point"
sounds fine but your choice of "current JSON resource" doesnt make
sense to me: you rely on the context of the call that retrieved the
object to determine "current resource," not the object from which the
reference is being determined. If the target reference isnt already
resolvable with in other information from the same call (say, it'd
already been transfered and the server opted not to resend on that
account) it requires inordinately complex resource path handling to
resolve. It also means $ref's will be constantly changing depending
on where they're accessed from. Instead of providing a reproducible
reference you've now turned the reference into something that is only
useful for that particular object access. In implementation terms,
you have to mark that there was a reference and the reference target,
then for any follow up serialization call you have to rebuild the
reference for that particular call. This all roots from the same
cause: you are floating the context of your references by the root of
the object being returned in the call, and the damage is that basis
may change if you access the reference by any other path: its a
lexical continuation. I would fight tooth nail and claw to make sure
current context is not so fickle and requires so much contextual
backing store. The "current context" I expect would be "this", the
object making the reference. This object can reference its own
children. Or it can reference an absolute path.

This parallels my issue with "relative uri's only" in the beginning.
If I have /people/rektide as {person:rektide, posts:[{'$ref':'../posts/
1'}] and /people/kris/friend/rektide/ now I have to modify my
serialization to display the same data. Id rather reference "/posts/
1". The $ref issue is the same. If /people/kris is
{"my_id":"1","foo":[{"bar":3},{"$ref":"#.foo[0]"}]} and I want to
access it from /people/rektide/friends now I have to update my '$ref'
to '#.[0].foo[0] by remembering that the .foo[2] is a continuation of /
people/kris.

How do I partially update nested elements?

I would like the server to be able to indicate a range without the
client having requested one. The client might not know what range to
request (intelligent reply to an If-Modified-Since), or the server
might simply be unwilling to send over seventeen million records yet
want to be more helpful / less ambiguous than some 4xx or 5xx.

Jeni Tennison

unread,
Sep 11, 2008, 5:00:54 PM9/11/08
to restfu...@googlegroups.com
Kris,

My next comment is a suggestion about "Property Path Based Referencing".

I'm a little sceptical about whether this is the best way of dealing
with shared resources. I think that if a resource is important enough
that I need to refer to it, then it ought to have a proper URI.

However, putting that aside, I think you could usefully describe this
as defining a restriction on the fragment identifier syntax for the
application/json media type. The URI spec [1] says:

Individual media types may define their own restrictions on or
structures within the fragment identifier syntax for specifying
different types of subsets, views, or external references that
are identifiable as secondary resources by that media type. If
the primary resource has multiple representations, as is often
the case for resources whose representation is selected based on
attributes of the retrieval request (a.k.a., content negotiation),
then whatever is identified by the fragment should be consistent
across all of those representations. Each representation should
either define the fragment so that it corresponds to the same
secondary resource, regardless of how it is represented, or
should leave the fragment undefined (i.e., not found).

I'd suggest that you base this on RFC 3986 rather than RFC 2616, since
it's more up to date. With that as the basis, you could just say:
json-reference = "{" <"> "$ref" <"> ":" <"> URI-reference <"> "}"
and then specify that fragment identifiers for application/json are of
the form:

fragment = +property-segment

Also, note that the URI spec says that fragment identifiers should be
accessible across representations of the same resource. So if I had an
HTML version of /Person/1 and a JSON representation of /Person/1 it
would be nice if I could use the same fragment identifier in the URI
to point to the children of each.

That being the case, it would be useful to remove the leading '.' from
the first property segment in the fragment identifier, as these aren't
allowed as the first character of an HTML ID. That way, /Person/
1#children would be meaningful in both representations.

So I'd suggest:

fragment = property-segment *("." property-segment)
property-segment = token | ("[" 1*DIGIT "]") | ("[" single-quoted-

string "]")
single-quoted-string = "'" *(<any TEXT except "'"> | single-quoted-
pair) "'"
single-quoted-pair = "\" CHAR

although I'm also not sure how #['children'] would be any different
from #children?

Cheers,

Jeni

[1]: http://www.apps.ietf.org/rfc/rfc3986.html#sec-3.5

Jeni Tennison

unread,
Sep 11, 2008, 5:28:32 PM9/11/08
to restfu...@googlegroups.com
Kris,

Another set of questions/comments are around Paging.

I do like the idea of using the existing Content-Range/Range/If-Range
HTTP headers to manage getting particular items from collections. But...

1. What happens with collections that are sub-resources, such as the
"accounts" collection in one of my previous posts. How can the
application request just the first five accounts? (Or the server
indicate that just the first five accounts have been returned?)

2. Passing around *textual sections* of the JSON array seems like a
bad idea to me. It makes things difficult for the client receiving the
range, because it can't be parsed normally. Do you have experience
with non-JSON-aware proxies that see a

Content-Range: items 0-9/20

header performing basic concatenation in order to reconstruct a
resource? I'd expect them to ignore range units they don't understand.

Cheers,

Kris Zyp

unread,
Sep 11, 2008, 5:59:12 PM9/11/08
to restful-json
> Good stuff.
>
> If I wish to hyper-reference a /posts collection from the /people
> collection, I have to {"$ref": "../posts/1"} ? Is that right? Why
> are absolute uri's not permitted? We'll see this problem flare to far
> greater proportions shortly.

Absolute URI are absolutely allowed. Did I say something in the proposal to
suggest otherwise? Perhaps my examples are more geared toward relative URIs
because I expected that they would be useful in allowing data to be
represented with minimal modification. I like absolute URIs though :).

> The property path reference threw my head for a loop. I would like to
> see more examples of valid path references. Your BNF notation
> introduces absolute URI's which are not references and there are no
> examples for.

The intention is that you could write:
{
"id":"kris",
"accounts":[{"$ref":"http://site.com/user/joe#.accounts[1]"}]
}
This would indicate that the first object in my accounts array should be the
same object as the second object in the accounts array for the object
located at http://site.com/user/joe.


> The phrase "If the reference starts with # instead of object location,
> the current JSON resource should be considered the starting point"
> sounds fine but your choice of "current JSON resource" doesnt make
> sense to me: you rely on the context of the call that retrieved the
> object to determine "current resource," not the object from which the
> reference is being determined. If the target reference isnt already
> resolvable with in other information from the same call (say, it'd
> already been transfered and the server opted not to resend on that
> account) it requires inordinately complex resource path handling to
> resolve. It also means $ref's will be constantly changing depending
> on where they're accessed from. Instead of providing a reproducible
> reference you've now turned the reference into something that is only
> useful for that particular object access. In implementation terms,
> you have to mark that there was a reference and the reference target,
> then for any follow up serialization call you have to rebuild the
> reference for that particular call. This all roots from the same
> cause: you are floating the context of your references by the root of
> the object being returned in the call, and the damage is that basis
> may change if you access the reference by any other path: its a
> lexical continuation. I would fight tooth nail and claw to make sure
> current context is not so fickle and requires so much contextual
> backing store. The "current context" I expect would be "this", the
> object making the reference. This object can reference its own
> children. Or it can reference an absolute path.

Is there anything in here that is different than how relative URIs are
handled/resolved in HTML with hyperlinks? The intent is to essentially
follow the same rules.

>
> This parallels my issue with "relative uri's only" in the beginning.
> If I have /people/rektide as {person:rektide, posts:[{'$ref':'../posts/
> 1'}] and /people/kris/friend/rektide/ now I have to modify my
> serialization to display the same data. Id rather reference "/posts/
> 1". The $ref issue is the same. If /people/kris is
> {"my_id":"1","foo":[{"bar":3},{"$ref":"#.foo[0]"}]} and I want to
> access it from /people/rektide/friends now I have to update my '$ref'
> to '#.[0].foo[0] by remembering that the .foo[2] is a continuation of /
> people/kris.

Consistently using id/URIs makes life much saner, I agree. Path referencing
exists for situations where data doesn't and can't have any locator
property.

> How do I partially update nested elements?

I was thinking we could allow multi-property paths in the "properties" range
unit:
Content-Range: name, subobject.foo, subobject.bar

> I would like the server to be able to indicate a range without the
> client having requested one. The client might not know what range to
> request (intelligent reply to an If-Modified-Since), or the server
> might simply be unwilling to send over seventeen million records yet
> want to be more helpful / less ambiguous than some 4xx or 5xx.

So maybe the server could include a Content-Range even if not asked for one?

Kris

Kris Zyp

unread,
Sep 11, 2008, 6:04:30 PM9/11/08
to restful-json


On Sep 11, 1:48 pm, Jeni Tennison <jeni.tenni...@googlemail.com>
wrote:
> Kris,
>
> On 5 Sep 2008, at 16:33, Kris Zyp wrote:
>
> > Below is my proposal for a RESTful JSON protocol, called JSON  
> > resources.
>
> This is a really useful proposal, especially given that it's based on  
> so much existing practice. I have several questions about it, some of  
> which I'll put in separate emails so that they're easier to track.
>
> My first group of questions is about sub-resources that are collection  
> resources. Say I have:
>
> Location: /user/
> Content-Type: application/json; locator=id
>
> [{"id": "jdoe",
>   "name": "John Doe",
>   "accounts": [{"site": "google.com",
>                 "username": "john.doe"},
>                {"site": "flickr.com",
>                 "username": "johnny"}]}
>   ...]
>
> Here, the accounts property holds a collection resource (an array of  
> objects). Let's say that the canonical location of each of those  
> "account" resources is of the form:
>
>   /user/{user.id}/account/{account.site}
>
> Does the "locator property" specified in the Content-Type carry  
> through into the sub-resources or not? Do I have to do:

That is the intention, and with my work I have felt it is easiest to
express sub-subresources that are within different record stores using
a single identity/locator property convention:
[{"id": "jdoe",
"name": "John Doe",
"accounts": [{"id": "/account/132",
"site": "google.com",
"username": "john.doe"},
{"id": "/account/233",
"site": "flickr.com",
"username": "johnny"}]}]
The canonical location for the account sub-resources should be pretty
clear here.
However, I have certainly seen URI structure you describe, which forms
a two-property/column unique key for records. I believe ActiveResource
has popularized it to some degree. Based on the raw data (without
extra insertion of unique keys), you essentially want to use the
"site" property as the locator property in combination with id
property at the top level. I had considered addressing this in the
proposal, but wasn't sure if it was really needed. If it is really
needed, I was thinking we could have a more extensive schema-structure
based solution that had more extensive information about how to map
objects. This could be part of the schema that clients do download for
information on the expected structure of data (since the mapping would
be more dependent on complex data structure).

>
> to indicate the URI of each of those resources? Or am I expected to  
> use "$ref" here:

The intended difference between the locator property ("id" or
otherwise) and "$ref" is that "$ref" indicates that the object is not
fully included/represented in place (although some properties may be
included, but it doesn't represent a full representation).

> Anyway, this leads nicely to the question of how an application could  
> know that the array held in the "accounts" property is a collection  
> resource that is POSTable to at /user/jdoe/account/. Do I have to do:
>
> Location: /user/
> Content-Type: application/json; locator=id
>
> [{"id": "jdoe",
>   "name": "John Doe",
>   "accounts": {"$ref": "jdoe/account/"}}
> ...]
>
...
> In this case, there's no way to tell from the /user/ collection that  
> the accounts property holds another collection resource rather than a  
> normal resource (because the "accounts" property no longer holds an  
> array). Or is the presence of the '/' at the end of the URI sufficient  
> to indicate this?

This seems like further evidence that a separately requestable schema
could assist the generic client:
GET /user HTTP/1.1 # get the schema

response:
{
identity:"id",
properties:{
accounts:{
type:"array",
identity:"site",
urlMapping:# maybe a uri-template?
},
name:{type:"string"}
}
}

...
> or you might have a separate description document that provided both  
> the schema and the URI bindings for such properties.

I like that :).

Kris

Kris Zyp

unread,
Sep 11, 2008, 6:10:04 PM9/11/08
to restfu...@googlegroups.com
> I'd suggest that you base this on RFC 3986 rather than RFC 2616, since
> it's more up to date. With that as the basis, you could just say:
> json-reference = "{" <"> "$ref" <"> ":" <"> URI-reference <"> "}"
> and then specify that fragment identifiers for application/json are of
> the form:
>
> fragment = +property-segment
>
> Also, note that the URI spec says that fragment identifiers should be
> accessible across representations of the same resource. So if I had an
> HTML version of /Person/1 and a JSON representation of /Person/1 it would
> be nice if I could use the same fragment identifier in the URI to point
> to the children of each.
>
> That being the case, it would be useful to remove the leading '.' from
> the first property segment in the fragment identifier, as these aren't
> allowed as the first character of an HTML ID. That way, /Person/
> 1#children would be meaningful in both representations.
>
> So I'd suggest:
>
> fragment = property-segment *("." property-segment)
> property-segment = token | ("[" 1*DIGIT "]") | ("[" single-quoted-
> string "]")
> single-quoted-string = "'" *(<any TEXT except "'"> | single-quoted-
> pair) "'"
> single-quoted-pair = "\" CHAR

Sounds good to me.

> although I'm also not sure how #['children'] would be any different from
> #children?

Do you think it would be better if there was an absolute definition for when
one should be used versus the other? That is the contents of a
single-quote-string in a [] must not be a valid token, so #['children']
would be illegal (must be #children) and ['string'] would only be allowed
for properties with special characters like #['the children'].

Kris

Kris Zyp

unread,
Sep 11, 2008, 6:17:44 PM9/11/08
to restfu...@googlegroups.com
> Another set of questions/comments are around Paging.
>
> I do like the idea of using the existing Content-Range/Range/If-Range
> HTTP headers to manage getting particular items from collections. But...
>
> 1. What happens with collections that are sub-resources, such as the
> "accounts" collection in one of my previous posts. How can the
> application request just the first five accounts? (Or the server indicate
> that just the first five accounts have been returned?)

Good question, I was just anticipating that sub-arrays are generally smaller
collections (vs the large collections that are often represented by
top-level resources), and so ranges wouldn't be as necessary, or at least
you could avoid the need by structuring your data in this way. One could
have a response that hyper-referenced the array when large arrays are used
and then the accounts could be a top-level array for the next request (which
could have a Range). Certainly open to other ideas though...

> 2. Passing around *textual sections* of the JSON array seems like a bad
> idea to me. It makes things difficult for the client receiving the range,
> because it can't be parsed normally. Do you have experience with
> non-JSON-aware proxies that see a
>
> Content-Range: items 0-9/20
>
> header performing basic concatenation in order to reconstruct a resource?
> I'd expect them to ignore range units they don't understand.

Keeping ranged responses as valid JSON does make it easier for clients to
parse. I specified textual sections because the HTTP working group suggested
that alternate range units should maintain the property of being purely
textually concatenateable. I really have a strong preference either way. I
guess if I had to choose I would actually go with valid JSON (vs textual
sections as in my proposal), just becuase that is what I currently have
implemented.

Thanks,
Kris

Dave Scheffer

unread,
Sep 12, 2008, 7:53:59 AM9/12/08
to restfu...@googlegroups.com
Given the overhead of the markup it may as well be XML - then at least we'd
have a cross-protocol implementation.

--------------------------------------------------
From: "rektide" <rek...@gmail.com>
Sent: Thursday, September 11, 2008 3:54 PM
To: "restful-json" <restfu...@googlegroups.com>
Subject: [restful-json] Re: JSON Resources: A proposal for a RESTful JSON
protocol

>

Nikunj Mehta

unread,
Sep 12, 2008, 7:52:03 PM9/12/08
to restful-json
Hi Kris,

I must commend your effort to address every issue raised about your
proposal. I have watched from the sidelines as this discussion has
evolved, waiting for a chance to thoroughly vet your proposal. Now
that I have gone through it I want to share some feedback. Look at it
not as mere criticism, but as an opportunity to win new friends and
develop consensus on this important topic.

I have some experience on the Atompub working group and am familiar
with the reasoning process we went through. Secondly, I have
implemented a proxy-cache for Atompub which enables greater
responsiveness and disconnected operation. Finally, I have a feeling
that an elegant approach to deal with all that data sitting inside
databases so that one can interact with it from new classes of
applications is a very potent one.

There is no world of JSON resources; there is, however, a Web of JSON
representations. You may say what's in the name. For me, thinking
seeps through the name, and making the name more inclusive would
definitely help broaden the reader's perspective.

Firstly, let's agree that we are dealing with JSON data and
representations and not JSON documents. I think this distinction is
critical since the data is far more structured than that possible with
XML documents. Secondly, let's recognize the fact that a number of
applications are already supporting both an Atom and a JSON
representation of their resources, even though they may not offer a
protocol for their manipulation. It is beneficial to be able to
connect these two worlds, So let's not pretend in one that the other
does not exist (remember the network effects of rich interlinkages).
Thirdly, let's make provisions for collection-level metadata to be
incorporated in the syntax because if we don't the syntax will most
likely be unable to be extended for purposes where collection-level
metadata is required. Can someone make a case for not defining any
standard metadata other than for referencing? Not even for
collections? From Jeni's complaint about the need to identify an
updateable collection, it seems that some metadata is unavoidable in
that case.

Finally, let's recognize the role that JavaScript plays in the browser
and the need for JSON resources to be used independently of headers
for the most straightforward use cases. For example, it is not very
useful to rely on the Content-Type header to find out the unique
locator, since in my application, I may not be able to access the
response headers on a JavaScript resource request.

Specific feedback is called out below in the context of the original
proposal.

> JSON Resources Proposal
>
> JSON resources does not specify a JSON format, any valid JSON structure can be used with JSON resources. JSON resources does recommend a structure for hyper-referencing objects, but this structure can still be used with any JSON format, and it is not required.
IMHO, Atom and RSS have proven that there are significant benefits of
standardized metadata. Of course, document metadata tends to overwhelm
the data case, and so some caution is warranted. However, not having
any standardized metadata at all sounds too extreme. See these use
cases and decide for yourself:
* Updating a cache from some server (including origin) requires being
able to identify items and check staleness efficiently
* Presenting results of an unstructured search request to a human
reader

>
> Resource Locator Determination
> A central function of the JSON resources specification is determining the locator path for JSON resources. When a resource is retrieved through a request, the top-level resource that is returned in the response has an implicit locator, the same locator that was used to retrieve the resource. An alternate canonical locator can be provided by the server with the "Location" header as defined in the HTTP specification.
It helps to have a locator be stored in the resource's representation
returned by the server. This enables the client to determine the
address at which interaction may be performed with the server. In your
example, there is no implicit locator for a representation at all,
there is just a context. The Locator header is useless in applications
that do not have access to headers, such as when JSON is injected in
to a page through a script tag.
>
> JSON is hierarchical in nature.
JSON is certainly hierarchical in its syntax. However, the semantics
of hierarchy depends on the resource and not the representation.

> A top level JSON entity (object or array) may have objects that can be treated as resources as themselves. In order for these sub-entities to be properly treated as resources, a client must be able to determine the resource's locator path (URL).
It is hard to guarantee that the server (by way of the application)
allows locator paths to be created for any arbitrary node in the JSON
object representation hierarchy. This is the reason why REST requires
a means of identifying the server states supported by way of URLs. By
baking the requirement that each and every path implied by an object
structure is a URL, you are creating a bar that is unnecessarily high
for servers to use JSON as representation syntax. If this is
acceptable to the community, then who am I to stop them?

> An object's URL is determined from the object's locator property, treated as a relative URL.
This is the reason why rektide felt that using relative URL syntax is
mandatory.

>To calculate an object's URL, the URL used to retrieve the JSON document is the base URL and the value of the locator property is the relative URL. Then, the absolute URL can be computed based on RFC 1808's specification (http://www.ietf.org/rfc/rfc1808.txt).
There is benefit to defining a `$base` type of standard property to
allow xml:base like capability.

>
> A server can declare which property is the locator property for objects in an JSON document with a MIME parameter (MIME parameters are defined inhttp://tools.ietf.org/html/rfc2045#section-5). Alternate JSON sub-content types (like application/collections+json) may utilize a predefined JSON structure which indicates the locator property.
I tend to agree with Roy Fielding on the use of special properties to
identify objects uniquely. It is not clear what are the benefits of
using a special application-specific field for the identifier.
Moreover, all examples in this proposal are numeric, without
explicitly saying so and make it feel like Roy's suggestion about ids
cannot coexist with this proposal.

> When a MIME parameter is used to define the locator property. The MIME parameter name should be "locator" and the value should be the name of the locator property. For example if the content type of the resource was "application/json" (alternate subtypes are allowed), then the locator property can be declared by suffixing the content type, and the following JSON representation could be sent. If the a request was made tohttp://site.com/Person/, then the following response could be returned:
There is a problem with combining identifiers and locators. Atom very
elegantly separates the two and that enables syndication, local
storage, and relocation. My suggestion is to not rely heavily on the
identifier being treated as a (relative) URL. Combined with my
previous feedback on locators above, I am not in favor of using the
'locator' MIME property.

>
> Content-Type: application/json;locator=my_id
> [
> {"my_id":"1","name":"John Doe"},
> {"my_id":"2","name":"Jane Doe"}
> ]This resource representation would indicate that two subresources have been included. The first subresource has locator (computed by relative URL) ofhttp://site.com/Person/1and is represented by:
>
> {"my_id":"1","name":"John Doe"}If a request is made tohttp://site.com/Person/1with the same headers as the initial response, the server should respond with the representation shown above. If the client wishes to modify the resource it may request the modification by sending a PUT method and the representation of the resource with modifications.
>
> PUT /Person/1
>
> {"my_id":"1","name":"Jim Doe"}If the server permits the operation, the resource should be modified to match the provided representation. New properties that were not in the old version should be added, modified properties should be updated, and properties not listed in the old version should be deleted.
As said by Joe and Bill de hora, removal should be explicit [http://
groups.google.com/group/restful-json/msg/63d976adbb357e17]

>
> The client may request the deletion of the resource with the DELETE method:
>
> DELETE /Person/1
>Resource Creation
> New resources may be created by using a POST method with a collection resource, or a PUT method with an client defined location. A collection resource is a resource that returns an array of JSON values that represent subresources. To attempt to create a new resource in a collection, a client can make a POST request to the URL for the collection resource with a JSON value indicating the desired properties or values of the resource to be created.
This is a common REST anti-pattern - using both POST and PUT for
creating new resources. Unfortunately protocol design experience (with
WebDAV and Atompub) shows that these are "either/or and not both"
choices. I have dealt with applications that require unique identifier
generation and that creates an undesirable level of coupling between
clients and servers. Also remember that you have to always allow that
the server may not like the id chosen by the client, in which case the
client has to be prepared to deal with the consequences.

>For example:
>
> POST /Person/
>
> {"name":"Josh Doe"}This indicates that the client requests a new object be created with a "name" property with the value of "Josh Doe". If successful, the server respond with a response with a status of 201 Created. The response must also include a "Location" header that indicates the location of the newly created resource. For example:
>
> Location: /Person/3If the server does not support creation of resources in this manner, or the operation was unauthorized, the server should respond with the appropriate HTTP response status.
Experience with Atompub has shown that it is necessary to also provide
Content-Location header upon creation of a new resource so that the
representation returned in the response can be associated with that
Content-Location. This is frequently a good idea as it avoids a second
round-trip to access the representation of the newly created resource.

>
> A new resource may alternately be created with the PUT method. With the approach, the client provides the location for which it desires the resource to be accessible from in the future. The desired resource representation should still be included as with a POST method creation except that the client should include the appropriate locator property corresponding to the new resource's location. For example:
>
> PUT /Person/josh
>
> {"my_id":"josh","name":"Josh Doe"}If the operation is successful, the server should respond with a 201 status. The server may include a "Location" header indicating where the resource will be accessible from in the future, however this is not necessary if the client's defined location is acceptable to the server.
>
> Hyper References
> A JSON resource may utilize JSON referencing for linking to other resources. A property may utilize a reference to indicate that it's value can be determined by resolving the reference. An array item may also use a reference to indicate it's target value. A JSON reference is a JSON object with a property named "$ref", and a value indicating the location of the resource to be used as the value. The value can be resolved to a URL by relative URL computation in the same manner as the locator property. A client can use the computed URL to retrieve the resource to resolve the reference. For example, if a JSON resource retrieved fromhttp://site.com/Person/1 was represented:
At least within the Atom and HTML communities, ref is used to indicate
an ID reference. If you explicitly want to use a locator, I would
recommend using the name 'href'. Just one more character and this will
bridge the JSON community to the other major Web communities.
Continuing my previous theme of separating locators from identifiers,
here I support you that the hyperlinks should use locators as opposed
to identifiers. I also agree with Jeni's other feedback about the use
of context for resolving a relative URL.

>
> {"my_id":"1","name":"John Doe","spouse":{"$ref":"2"}}
> This would indicate that the "spouse" property's value is the JSON resource located at http://site.com/Person/2. If both subresources http://site.com/Person/1 and http://site.com/Person/2 were both provided within a single collection:
>
> [
> {"my_id":"1","name":"John Doe","spouse":{"$ref":"2"},
> {"my_id":"2","name":"Jane Doe","spouse":{"$ref":"1"}
> ]The client would not need to make any additional requests, but would know that the first object's spouse property's referent was the second object and vice versa.
>
> Property Path Based Referencing
<snip>
> A reference object is not limited to only have the "$ref" property. A reference object may include any properties from the target resource object. A reference object can include any property desired from the target resource object. Any properties included in a reference object should have the same value as the target resource object, with the exception that the properties that have a string value may use a truncation of the true value. Reference objects with partial sets of properties can be useful for efficient transfer of relevant information, while allowing clients to request more detailed information as needed
The 'should requirement' for referenced object's properties is too
stringent. Just like the truncation of string properties is left to a
server, other properties may provide approximate values for other
property types as well. Applications must know that they are required
to separately get the full representation of the referenced resource.

<snip>
> Partial Object Updates
> Normally, JSON resouces are updated in whole with a PUT operation. However, a PUT operation can update a subset of the properties of a JSON object using a partial update. To indicate a partial update, the client includes a Content-Range header with a properties range unit. The properties that should be affected by the update should be comma delimited after the "properties" range unit declaration. Properties may be tokens or quoted strings.
PUT is not allowed to be used to partially update a resource. There
has been vigorous debate for supporting partial updates [], and
current consensus is that a new HTTP method is required for these
semantics.

> PUT /Person/2
> Content-Range: properties name,"current age"
>
> {"name":"Kristopher", "current age",32}
> If a property is listed in the Content-Range header, but is omitted from the JSON object representation in the entity, this indicates that this property should be deleted.
What happens if a property is listed in the object but not in the
Content-Range?

Kris Zyp

unread,
Sep 13, 2008, 12:58:18 AM9/13/08
to restfu...@googlegroups.com
Thanks for the excellent thoughtful and extensive review. Most I agree with,
although of course I will take issue with a few things. Discussion inline...

> There is no world of JSON resources; there is, however, a Web of JSON
> representations. You may say what's in the name. For me, thinking
> seeps through the name, and making the name more inclusive would
> definitely help broaden the reader's perspective.

Good point, I generally agree. However, I do think it would naive to ignore
the fact there are certainly resources that are exist in structures that are
more naturally expressed in certain representations. Some information is
more intuitively expressed in JSON, some XML, some GIF, etc.

> Firstly, let's agree that we are dealing with JSON data and
> representations and not JSON documents. I think this distinction is
> critical since the data is far more structured than that possible with
> XML documents. Secondly, let's recognize the fact that a number of
> applications are already supporting both an Atom and a JSON
> representation of their resources, even though they may not offer a
> protocol for their manipulation. It is beneficial to be able to
> connect these two worlds, So let's not pretend in one that the other
> does not exist (remember the network effects of rich interlinkages).
> Thirdly, let's make provisions for collection-level metadata to be
> incorporated in the syntax because if we don't the syntax will most
> likely be unable to be extended for purposes where collection-level
> metadata is required. Can someone make a case for not defining any
> standard metadata other than for referencing? Not even for
> collections? From Jeni's complaint about the need to identify an
> updateable collection, it seems that some metadata is unavoidable in
> that case.
>
>
> Finally, let's recognize the role that JavaScript plays in the browser
> and the need for JSON resources to be used independently of headers
> for the most straightforward use cases. For example, it is not very
> useful to rely on the Content-Type header to find out the unique
> locator, since in my application, I may not be able to access the
> response headers on a JavaScript resource request.

I am not opposed to a JSON format for metadata, but I think it is important
that JSON representations that don't fit some JSON format for metadata can
still benefit from a protocol for RESTful JSON. I think that should be
separable (RESTful architectural protocol for JSON and a JSON REST metadata
format).

A top-level structure that includes metadata is not a great imposition,
forcing internal structures to follow a specific format where every object
that can be treated as a resource must have a particular object wrapper
would be too great of burden. One of the somewhat unique characteristics of
JSON, is that many information structures, particularly those within
applications have very definite, obvious, unambiguous representations in
JSON, forcing alternate representations would be anathema to JSON. I
included an example use case from my framework to hopefully illustrate this
point.

Another important concept that we should observe is progressive complexity.
Simple use cases should be simple with our protocol. More complexity should
be possible, but it should minimally impact the simplicity of simple use
cases.

>> Resource Locator Determination
>> A central function of the JSON resources specification is determining the
>> locator path for JSON resources. When a resource is retrieved through a
>> request, the top-level resource that is returned in the response has an
>> implicit locator, the same locator that was used to retrieve the
>> resource. An alternate canonical locator can be provided by the server
>> with the "Location" header as defined in the HTTP specification.
> It helps to have a locator be stored in the resource's representation
> returned by the server. This enables the client to determine the
> address at which interaction may be performed with the server. In your
> example, there is no implicit locator for a representation at all,
> there is just a context. The Locator header is useless in applications
> that do not have access to headers, such as when JSON is injected in
> to a page through a script tag.

I am a little confused, below you make suggestions about how to use headers
like Content-Location. Do you think some headers are ok, and some aren't?
Just curious why you dislike this rather standard HTTP header. Is it
necessary in the simple use case that JSONP provides?

I do certainly acknowledge that they are JSON transports (particularly
JSONP) that do not provide access to headers, but IMO, it seems more
appropriate to have a comprehensive HTTP-emulation strategy for such
transports than reinventing each header one-by-one. However, if everyone
feels this would be better in the representation entity, I can live with
that.

>> A top level JSON entity (object or array) may have objects that can be
>> treated as resources as themselves. In order for these sub-entities to be
>> properly treated as resources, a client must be able to determine the
>> resource's locator path (URL).
> It is hard to guarantee that the server (by way of the application)
> allows locator paths to be created for any arbitrary node in the JSON
> object representation hierarchy. This is the reason why REST requires
> a means of identifying the server states supported by way of URLs. By
> baking the requirement that each and every path implied by an object
> structure is a URL, you are creating a bar that is unnecessarily high
> for servers to use JSON as representation syntax. If this is
> acceptable to the community, then who am I to stop them?

I completely agree. That separation of mutable property-relationships and
immutable identities is essential, and is why I use identifier/locator
properties to determine URL instead of object structure based locators.

>> An object's URL is determined from the object's locator property, treated
>> as a relative URL.
> This is the reason why rektide felt that using relative URL syntax is
> mandatory.

I see, poor wording on my part.

>>To calculate an object's URL, the URL used to retrieve the JSON document
>>is the base URL and the value of the locator property is the relative URL.
>>Then, the absolute URL can be computed based on RFC 1808's specification
>>(http://www.ietf.org/rfc/rfc1808.txt).
> There is benefit to defining a `$base` type of standard property to
> allow xml:base like capability.

That's fine.

>>
>> A server can declare which property is the locator property for objects
>> in an JSON document with a MIME parameter (MIME parameters are defined
>> inhttp://tools.ietf.org/html/rfc2045#section-5). Alternate JSON
>> sub-content types (like application/collections+json) may utilize a
>> predefined JSON structure which indicates the locator property.
> I tend to agree with Roy Fielding on the use of special properties to
> identify objects uniquely. It is not clear what are the benefits of
> using a special application-specific field for the identifier.

The clarify the benefits:
1. Existing unique key property values can be reused to denote location.
2. Existing implementations behave this way
3. Existing implementations use different identifier properties

This section of the proposal isn't ex nihilo, it is largely based on
existing implementations.

> Moreover, all examples in this proposal are numeric, without
> explicitly saying so and make it feel like Roy's suggestion about ids
> cannot coexist with this proposal.

Perhaps it might be better to have this discussion under that thread, but I
thought Roy's suggestion was about using object structure for determining
locators, which I thought you just argued against (and I agreed);
object-structure locators inability to separate relationship and identity
seems pretty untenable.

>> When a MIME parameter is used to define the locator property. The MIME
>> parameter name should be "locator" and the value should be the name of
>> the locator property. For example if the content type of the resource was
>> "application/json" (alternate subtypes are allowed), then the locator
>> property can be declared by suffixing the content type, and the following
>> JSON representation could be sent. If the a request was made
>> tohttp://site.com/Person/, then the following response could be returned:
> There is a problem with combining identifiers and locators. Atom very
> elegantly separates the two and that enables syndication, local
> storage, and relocation. My suggestion is to not rely heavily on the
> identifier being treated as a (relative) URL. Combined with my
> previous feedback on locators above, I am not in favor of using the
> 'locator' MIME property.

I am not sure I understand the problem. Do you not like relative URLs?

>> PUT /Person/1
>>
>> {"my_id":"1","name":"Jim Doe"}If the server permits the operation, the
>> resource should be modified to match the provided representation. New
>> properties that were not in the old version should be added, modified
>> properties should be updated, and properties not listed in the old
>> version should be deleted.
> As said by Joe and Bill de hora, removal should be explicit [http://
> groups.google.com/group/restful-json/msg/63d976adbb357e17]

So you are suggesting PUT operations have a merging effect (all the
properties of the PUT'ed resource and the old version are to be combined)?
That seems terribly contrary to REST to me. If you were to do a PUT with an
HTML file and the new version had certain elements removed, it would seem
very strange to require that a server actually tried to compare the new
version to the old version to make sure items weren't removed without an
"explicit" operation.
In case I am misunderstanding are you, are you suggested that if I do:
PUT /user/kris
{
"name":"kris",
"age":30,
"foo":"bar"
}

PUT /user/kris
{
"name":"kris",
"age":30
}
That the second request would have not cause any change to the object? I
hope I am misunderstanding.

>> The client may request the deletion of the resource with the DELETE
>> method:
>>
>> DELETE /Person/1
>>Resource Creation
>> New resources may be created by using a POST method with a collection
>> resource, or a PUT method with an client defined location. A collection
>> resource is a resource that returns an array of JSON values that
>> represent subresources. To attempt to create a new resource in a
>> collection, a client can make a POST request to the URL for the
>> collection resource with a JSON value indicating the desired properties
>> or values of the resource to be created.
> This is a common REST anti-pattern - using both POST and PUT for
> creating new resources. Unfortunately protocol design experience (with
> WebDAV and Atompub) shows that these are "either/or and not both"
> choices. I have dealt with applications that require unique identifier
> generation and that creates an undesirable level of coupling between
> clients and servers. Also remember that you have to always allow that
> the server may not like the id chosen by the client, in which case the
> client has to be prepared to deal with the consequences.

I am fine with just having one, this specification was mainly just codifying
the behavior of current servers that support both and seemed like POST was
more appropriate for server identifier assignment, and PUT was more
appropriate for client identifier assignment. Here is CouchDB's interface:
http://wiki.apache.org/couchdb/HttpDocumentApi

Do you recommend only specifying POST? Sounds great to me.

>> Location: /Person/3If the server does not support creation of resources
>> in this manner, or the operation was unauthorized, the server should
>> respond with the appropriate HTTP response status.
> Experience with Atompub has shown that it is necessary to also provide
> Content-Location header upon creation of a new resource so that the
> representation returned in the response can be associated with that
> Content-Location. This is frequently a good idea as it avoids a second
> round-trip to access the representation of the newly created resource.

Great suggestion. BTW, should inclusion of Content-Location be a SHOULD or
MUST?

>> Hyper References
>> A JSON resource may utilize JSON referencing for linking to other
>> resources. A property may utilize a reference to indicate that it's value
>> can be determined by resolving the reference. An array item may also use
>> a reference to indicate it's target value. A JSON reference is a JSON
>> object with a property named "$ref", and a value indicating the location
>> of the resource to be used as the value. The value can be resolved to a
>> URL by relative URL computation in the same manner as the locator
>> property. A client can use the computed URL to retrieve the resource to
>> resolve the reference. For example, if a JSON resource retrieved
>> fromhttp://site.com/Person/1 was represented:
> At least within the Atom and HTML communities, ref is used to indicate
> an ID reference. If you explicitly want to use a locator, I would
> recommend using the name 'href'. Just one more character and this will
> bridge the JSON community to the other major Web communities.

The intent with "$ref" was to avoid collisions with existing properties. I
like "href", but seems more likely to collide. And I certainly want to avoid
wrapping every object with containers that would possibly hold the href.

> Continuing my previous theme of separating locators from identifiers,
> here I support you that the hyperlinks should use locators as opposed
> to identifiers. I also agree with Jeni's other feedback about the use
> of context for resolving a relative URL.

My intent was to integrate the concepts of identifiers and locators for
simplicity. I am not sure I understand how you want to separate the two
(beneficially).

> <snip>
>> A reference object is not limited to only have the "$ref" property. A
>> reference object may include any properties from the target resource
>> object. A reference object can include any property desired from the
>> target resource object. Any properties included in a reference object
>> should have the same value as the target resource object, with the
>> exception that the properties that have a string value may use a
>> truncation of the true value. Reference objects with partial sets of
>> properties can be useful for efficient transfer of relevant information,
>> while allowing clients to request more detailed information as needed
> The 'should requirement' for referenced object's properties is too
> stringent. Just like the truncation of string properties is left to a
> server, other properties may provide approximate values for other
> property types as well. Applications must know that they are required
> to separately get the full representation of the referenced resource.

Sounds good.

> <snip>
>> Partial Object Updates
>> Normally, JSON resouces are updated in whole with a PUT operation.
>> However, a PUT operation can update a subset of the properties of a JSON
>> object using a partial update. To indicate a partial update, the client
>> includes a Content-Range header with a properties range unit. The
>> properties that should be affected by the update should be comma
>> delimited after the "properties" range unit declaration. Properties may
>> be tokens or quoted strings.
> PUT is not allowed to be used to partially update a resource. There
> has been vigorous debate for supporting partial updates [], and
> current consensus is that a new HTTP method is required for these
> semantics.

Sounds good. I was just trying to satisfy the goals that Ernest recorded in
the most HTTP-ish way I could think of. I have never implemented or needed
partial updates, so this was section was really of the top of my head. A new
method is fine with me.

>> PUT /Person/2
>> Content-Range: properties name,"current age"
>>
>> {"name":"Kristopher", "current age",32}
>> If a property is listed in the Content-Range header, but is omitted from
>> the JSON object representation in the entity, this indicates that this
>> property should be deleted.
> What happens if a property is listed in the object but not in the
> Content-Range?

I'll go with keeping the property (either way is fine with me).

I wanted to give an example from my framework, Persevere, to demonstrate a
use case for RESTful JSON with real application code. In Persevere all
database data is mapped to JavaScript objects within the server environment,
which can be accessed and modified like normal data with changes being
persisted (like ORM). The JavaScript objects are stored in the database and
are accessible through the REST api. On the server we can do something like:
me = new Person(); // creates a new Person object, server assigns an id
(user doesn't have to supply a id)
me.name="Kris";
me.address={state:"UT",city:"Sandy"};
//me.id -> 1
myWife = new Person();
myWife.name="Nikki";
myWife.friends=[me];
myWife.address=me.address;
//myWife.id -> 2

The JSON representation of my object/resource is unambiguous, forcing an
internal alterations to it seems unacceptable. The second resource leans on
hyper-referencing. Here is how I represent it:
GET /Person/

[
{id:"1","name":"Kris","address":{"state":"UT","city":"Sandy"}},
{id:"2","name":"Nikki","friends":[{"$ref":"1"}],"address":{"$ref":"1#address"}}
]

A top level structure would be ok:

{
"locator":"id",
... meta data ...
"result":[
{"id":"1", ...

But structure imposed on every element inside the array would seem to add a
lot of extra overhead and impose on the clear representation that JSON
provides.

Thanks
Kris

rektide

unread,
Sep 16, 2008, 5:30:41 PM9/16/08
to restful-json
Hiya again Kris, thanks for the speedy reply.

The absolute URI with path referencing you give looks good. That kind
of
accessibility into JSON is really what I'd like to see most in a JSON
spec! The #.
syntax "feels" a little goofy but works suprisingly well: its a little
more than just an
anchor (the server will return different data) but it is a reference
to a place in data,
and the . gives some kind of distinction that we're talking about
something different
from a regular anchor.

You're right that relative uri's in this proposal closely mirror
relative url's in html. I'll
back down some and claim perhaps there is no great danger to having
relative uri's,
but I do think it incurs quite a complexity cost for consumers.

> > How do I partially update nested elements?
>
> I was thinking we could allow multi-property paths in the "properties" range
> unit:
> Content-Range: name, subobject.foo, subobject.bar

I see nothing objectionable about this. I do have another issue
though.

How do I delete a property? Nulling out a value will still leave the
key on the object.

> > I would like the server to be able to indicate a range without the
> > client having requested one. The client might not know what range to
> > request (intelligent reply to an If-Modified-Since), or the server
> > might simply be unwilling to send over seventeen million records yet
> > want to be more helpful / less ambiguous than some 4xx or 5xx.
>
> So maybe the server could include a Content-Range even if not asked for one?

I havent fully considered the implications but that would be what I
would suggest.

rektide

John Cowan

unread,
Sep 16, 2008, 6:27:16 PM9/16/08
to restfu...@googlegroups.com
On Tue, Sep 16, 2008 at 5:30 PM, rektide <rek...@gmail.com> wrote:

>> > I would like the server to be able to indicate a range without the
>> > client having requested one. The client might not know what range to
>> > request (intelligent reply to an If-Modified-Since), or the server
>> > might simply be unwilling to send over seventeen million records yet
>> > want to be more helpful / less ambiguous than some 4xx or 5xx.
>>
>> So maybe the server could include a Content-Range even if not asked for one?
>
> I havent fully considered the implications but that would be what I
> would suggest.

Indeed, the server should be able to send a range different from what
the client requested, if the request is either off the end of the
collection or too large. The client can thereby request a chunk and
then page depending on what it gets back. At most there will be one
extra request with an error response.

> rektide
>

--
GMail doesn't have rotating .sigs, but you can see mine at
http://www.ccil.org/~cowan/signatures

Reply all
Reply to author
Forward
0 new messages