users@jersey.java.net

Re: [Jersey] Putting the RESTful "connectedness" around my existing Domain objects

From: Brett Dargan <brett.dargan_at_gmail.com>
Date: Fri, 1 May 2009 09:58:00 +1000

There has been a discussion titled [Jersey] Putting the RESTful
"connectedness" around my existing Domain objects on the jersey mailing list
that is starting up again.

I don't think I have confused HATEOAS with "connectedness", I have a
reasonable understanding of resource state, application state and HATEOAS.

See http://www.stucharlton.com/blog/archives/000141.html and this
discussion,
http://tech.dir.groups.yahoo.com/group/rest-discuss/message/12497, which I
see you have contributed to.

I think this final point made by Roy is pretty applicable here:

A REST API should be entered with no prior knowledge beyond the initial URI
(bookmark) and set of standardized media types that are appropriate for the
intended audience (i.e., expected to be understood by any client that might
use the API). From that point on, all application state transitions must be
driven by client selection of server-provided choices that are present in
the received representations or implied by the user’s manipulation of those
representations. The transitions may be determined (or limited by) the
client’s knowledge of media types and resource communication mechanisms,
both of which may be improved on-the-fly (e.g., code-on-demand). [Failure
here implies that out-of-band information is driving interaction instead of
hypertext.]


My point is you can't adhere to the HATEOAS constraint, without providing
links between resources so the server can guide the client to other
application states.

I agree that forms are a better example for explaining state transitions,
especially since resource state is likely to be changed by providing forms
(as will the User Agent, as Roy mentions); or equivalent form
templates/prototypes for other media types.
But to me providing forms or equivalents for other media types is a
different and easier problem to solve.

I'm very interested in how to evolve existing systems; I want to leverage
the vast islands of information that already exist.

I just want to do it in an elegant way from a code and a web perspective,
including the fact that uri's shouldn't change.

In a standard, layered design, you would have these components (see Image):

1. Code-On-Demand
2. View
3. Controller
4-6. Contains the Proposed Abstractions
7. Model
8. Persistent Store - Db; file; jcr; webdav
9. Proxies


Here are some options I have for adding links around some existing system
(there are likely more)

Due to the time constraints, the Pros, will be sparse.

Option 1: Add Links via Code-On-Demand.
Add links to my html page via javascript.
I could take my existing html representation and use dhtml to add links.

Cons:
* code-on-demand not available for all user agents or may be disabled
* Proxies can't cache the entire representation
* leak of possible application states to clients that don't need to know
* Detailed knowledge of resource and subresources required to provide "link
rich" representations
* Alternative media types may require alternative languages or structure to
perform add the links. ie. use of xsl for xml; javascript with svg.

Option 2: Add Links via Views

Cons:
* We all know this is bad
* Detailed knowledge of resource and subresources required to provide "link
rich" representations
* different views/media types require the same logic and detailed knowledge
of the model
* different views/media types may require some application state knowledge.
an admin user may have other links than anon.

Option 3: Add Links via Controllers
Pros:
* Can handle the inclusion/exclusion of links depending on the current
application state, regardless of the media type to respond with

Cons:
* Detailed knowledge of resource and subresources required to provide "link
rich" representations

Option 4: Add Links via Models
Pros:
* Detailed knowledge of the model and related models belong in the Model

Cons:
* Detailed knowledge of resource links aren't the domain of the models
* Not all possible related models are likely to be represented; to balance
performance with types of usage, often some relationships are not modelled,
so as to not eager load, very large graphs etc.
* Links are very static, The "next available" application state, still needs
to be determined in another layer, like Controller

Option 5: Add Links via Persistent Store

Store partial links in the db

Pros:
* Db driven, easy to update
* Tables have relationships
* easy adoption path
* easy to link to external resources, or resources outside your db schema
* easy to share links at db level, if several systems integrate at that
level
* Good for sparse relationships.

Cons:
* Update to change a link, will not play nice with intermediaries nor "cool
uris, that don't change"
* Not great for consistent dense relationships, you probably want to model
that differently. So with a Parent Child relationship, you wouldn't want
something in addition to existing foreign key relations, to redundantly
specify that to get to the children of a parent you have a list of
/child/xyz links. but by having that specified in the URITemplateAspect then
you are managing that once, close to the data.
* Relationships are not always defined in Foreign Keys
* Links are very static, The "next available" application state, still needs
to be determined in another layer, like Controller
* Only a partial solution for more dynamic aspect of determining what
application states make sense, still needs to be done in another layer.
* May be invasive, links stored in columns or other tables, no good if
you've got a locked down schema.

Thoughts
Models shouldn't have relationships to hardcoded resources, like
"/resource/50", but they could have a semantic relationship to
"/resource/{id}" or "/resource/{id};role={role}" under certain conditions.

There is a place for such LinkAwareModels (Component no. 5), as long as the
links are isolated and only contain semantic relationships, they are not
urls.

The Links from Models to Resources are isolated and encapsulated within its
own abstraction; which gives us component no. 6 URITemplateAspects (maybe
just simplify this to LinkTemplateAspect).

Possible "Application States" are dependent on the request, even though a
request must be STATELESS, possible "Application States" may still be
determined by the security access; restrictions of media-types or client,
which should all be part of the request. If you do stuff with user roles,
then make sure you encode within your url.

Component no. 4 is our LinkTemplateProcessor(s) and its responsibility is to
evaluate URITemplates within the LinkAwareModels/entities and to determine
appropriate state transitions based on the request.

This leads us to the final Option ( well, for this post ;) )

Option 6: Semantic relationships of a "Model to resources" defined via
URITemplateAspect and a LinkTemplateProcessor to evaluate the relationships
(URITemplates) and sub-entities to determine possible "application states"
Pros:
* Detailed knowledge of the model and related models belong in the Model
* Detailed knowledge of the model to resource of interest is a concern
isolated in the URITemplateAspects
* Any possible relationships to other resources can be defined
* Links are very dynamic. The possible state transitions can be determined
by the LinkTemplateProcessor, but it can do so decoupled from the detailed
relationships of the model to other resources.

The semantic relationships that are defined in the LinkAwareModels, can
include uri and other attributes, like rel. The LinkTemplateProcessor can
evaluate a lot of the current application state (but not all as the User
Agent may have representations from other servers or representations that
have been modified by Code-On-Demand) in combination with the semantic
relationship to determine the ultimate value of the link to use (relative
preferred, of course) and it can determine if that link is a valid state
transition. Only if you are an admin do you see this link; or the link
retains the current media-type used for this request; so a request for
/country/AU.html includes links to cities.html, not just cities. The default
negotiation might be something if that is not specified.

* The Processor can operate on objects, prior to rendering to a particular
media-type, so if you have a single object model that can render to multiple
media-types, you could have less code

Conclusion
What do you call, this, maybe Rich Interconnected Model View Resource RIMVR.
Rich in relation to having deep links within a resource representation and
from the applicability of those links. That actual uri templates are
evaluated late and with some context of the request and application state.

The use of these abstractions, in no way make an application RESTful, that
is up to the developers, but hopefully by following some abstractions, like
these we will get some clean code and some better understanding of RESTful
APIs.

I have some old code, to show this working.
One day I'll get a chance to clarify terms and simplify the code ;)