Hello Pablo,
Thanks for the runthrough... comments below..
Pablo Castro wrote:
[snip]
We model related entries or feeds using a link with a "rel" attribute of "related", and with
a "type" of either "application/atom+xml;type=feed" or "application/atom+xml;type=entry"
depending on the cardinality of the other end of the association.
One tricky aspect is that we need to indicate which association it is. At the model level
we have a "navigation property" that identifies the starting "end" of the association (e.g.
"Attendees", "Venue"). We currently put that name in the "title" attribute of the link.
That solution is not perfect, as we try not to overload constructs that are for human-readable
content. However, the alternative is to use a custom attribute, and we've been trying not to
introduce custom attributes unless absolutely needed. Another option would be to use different
"rel" values to specify the relationship, which feels natural but makes it much less likely
that generic processors will be able to do something interesting with it.
Most generic processors aren't doing much with links yet anyway. Using
specific rel attribute values would be better.
Do these trade-offs sound reasonable? Is any of the other options more
appropriate?
Continuing with the Events sample, this is what an entry (/Events(456)) with
links looks like:
<entry xml:base="http://localhost:81/EventsSample/"
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
xmlns="http://www.w3.org/2005/Atom"
m:type="EventsSample.Event">
<id>http://localhost:81/EventsSample/Events(456)</id>
<title type="text"></title>
<updated>2008-02-17T02:52:38Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Event" href="Events(456)" />
<link rel="related" type="application/atom+xml;type=entry" title="Venue"
href="Events(456)/Venue" />
<link rel="related" type="application/atom+xml;type=feed" title="Attendees"
href="Events(456)/Attendees" />
I'd much rather see this:
<link
rel="http://schemas.microsoft.com/ado/2007/08/dataservices/venue"
type="application/atom+xml;type=entry"
title="Venue"
href="Events(456)/Venue" />
<link
rel="http://schemas.microsoft.com/ado/2007/08/dataservices/attendees"
type="application/atom+xml;type=feed"
title="Attendees"
href="Events(456)/Attendees" />
<content type="application/xml">
<d:EventID m:type="Int32">456</d:EventID>
<d:Name>Big Party</d:Name>
<d:NoteToAttendees>It's going to be a great party!</d:NoteToAttendees>
<d:DateAndTime m:type="DateTime">2008-03-05T06:00:00</d:DateAndTime>
</content>
</entry>
FWIW, your content element is incorrect. There needs to be a top level
element, e.g.
<content type="application/xml">
<d:foo>
<d:EventID m:type="Int32">...</d:EventID>
<d:Name>...</d:Name>
<d:NoteToAttendees>...</d:NoteToAttendees>
<d:DateAndTime m:type="DateTime">...</d:DateAndTime>
</d:foo>
</content>
> [snip]
2. Expanding links inline
[snip]
How link expansion is requested is outside of the atom-syntax problem space, so
I'll just briefly state what we currently do in case you have an opinion: data services
support the query string option "$expand" to request link expansion. So you could say
"/Events?$expand=Attendees " to retrieve all Events and all contacts that are attendees
for each of them, or "/Events(456)?$expand=Attendees" to retrieve a single event (with
key 456) and its attendees. Expand syntax allows for deep expands such as
"Attendees/BestFriend" (expand Attendees, and on the expanded entry(es) expand BestFriend)
and wide expands such as "Venue, Attendees/BestFriend" meaning expand two immediate links,
and for the Attendees one further expand its BestFriend link.
Works for me :-)
For representing expanded links we put the expanded content inside the link element itself.
According to section 4.2.7 of RFC 4287:
"The "atom:link" element defines a reference from an entry or feed to a Web resource.
This specification assigns no meaning to the content (if any) of this element."
So it seems that adding content to the link element is not disallowed and at the same time
it does not overlap with any existing semantics given to such construct. Based on that we
thought it would be the perfect place for this information, as the link itself already
contains the metadata about the link that we needed.
+1. This is an excellent use of the extensibility of Atom.
When a client indicates that the target of a link should be expanded, the server responds
with the Atom representation of the resources pointed at by links wrapped in an <inline>
element. For example, for "/Events(456)?$expand=Attendees,Venue" the response would be:
[snip]
<link rel="related" type="application/atom+xml;type=entry" title="Venue"
href="Events(456)/Venue">
<m:inline>
<entry m:type="EventsSample.Venue">
<id>http://localhost:81/EventsSample/Venues(789)</id>
<title type="text"></title>
<updated>2008-02-17T03:01:18Z</updated>
<author>
<name />
</author>
<link rel="edit" title="Venue" href="Venues(789)" />
<link rel="related" type="application/atom+xml;type=entry" title="SalesContact"
href="Venues(789)/SalesContact" />
<content type="application/xml">
<d:VenueID m:type="Int32">789</d:VenueID>
<d:Name>The Cool Place</d:Name>
<d:Description>Great place for parties!</d:Description>
<d:Capacity m:type="Int32">1500</d:Capacity>
<d:Type>Nightclub</d:Type>
</content>
</entry>
</m:inline>
</link>
[snip]
I like this approach very much. Existing (properly implemented)
processors will be able to safely ignore the inline content without loss
of function and would still have the ability to extract useful
information from the document.
I focused on the GET operations above. We think it would be better to stay away from
attempting to support full modification operations on expanded graphs. In particular,
we do not handle PUT on more than one entry at a time today. We do support POSTing an
expanded graph, and we simply create all the nested entries and link them to the
parent entry, creating the whole graph in a single operation.
Sounds good. PUT would definitely be problematic.
- James
Feedback in general about this approach would be greatly appreciated.
(also posted this in the Astoria team blog)
Thanks
-pablo