While going through application scenarios for the ADO.NET Data Services 
Framework (Project Astoria) one of the first things we noticed is that 
data-centric applications usually want to bring down graphs of related 
resources in each interaction with the server. For example, if you are 
retrieving a resource that represents an "Event", you may want to also bring in 
the set of related Contact resources that are invited or the "Venue" resource 
where the event will take place. This write up briefly describes how we model 
associations between resources as Atom links and proposes a usage pattern of 
the atom:link element to support retrieving resource graphs in a single 
response. We're looking for feedback on the approach and also to get folks 
thinking about inlined content and whether it should be considered an extension 
to Atom.

More context on Astoria support for Atom here:
http://blogs.msdn.com/astoriateam/archive/2008/02/13/atompub-support-in-the-ado-net-data-services-framework.aspx


1. Links for modeling associations between resources

Related resources can be seen at the instance level as "links" in Atom terms. 
Of course, from the data application development perspective, it's interesting 
to make this discoverable at the service description (schema) level. In Astoria 
data services the underlying model is the Entity Data Model (EDM), which 
describes data in terms of "Entities" (instances of Entity Types) and 
associations between entities. In the context of the Atom interface, Entities 
are mapped to entries and Associations to links. So by looking at the service 
description a developer can discover the links that will be present in an entry 
of a given type.

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.

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" />
  <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>

>From the data modification perspective, links pointing to other resources in 
>the service can be specified in the payload of POST and PUT operations, to 
>establish links between the resource being manipulated and other existing 
>resources.

2. Expanding links inline

As I summarized at the beginning of this note, we want to enable clients to 
request whole sub-graphs of data starting at some resource or set of resources. 
There are two aspects that need to be addressed: how does the client indicate 
that it wants one or more links expanded and how are the expanded links 
represented on the response.

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.

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.

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:

<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-17T03:01:18Z</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">
    <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>
  <link rel="related" type="application/atom+xml;type=feed" title="Attendees" 
href="Events(456)/Attendees">
    <m:inline>
      <feed>
        <title type="text">Attendees</title>
        <id>http://localhost:81/EventsSample/Events(456)/Attendees</id>
        <updated>2008-02-17T03:01:18Z</updated>
        <link rel="self" title="Attendees" href="Events(456)/Attendees" />
        <entry m:type="EventsSample.Contact">
          <id>http://localhost:81/EventsSample/Contacts(123)</id>
          <title type="text"></title>
          <updated>2008-02-17T03:01:18Z</updated>
          <author>
            <name />
          </author>
          <link rel="edit" title="Contact" href="Contacts(123)" />
          <link rel="related" type="application/atom+xml;type=entry" 
title="BestFriend" href="Contacts(123)/BestFriend" />
          <content type="application/xml">
            <d:ContactID m:type="Int32">123</d:ContactID>
            <d:FirstName>John123</d:FirstName>
            <d:LastName>Doe123</d:LastName>
            <d:EmailAddress>[EMAIL PROTECTED]</d:EmailAddress>
            <d:Phone>123-456-123</d:Phone>
            <d:BirthDate 
m:type="Nullable`1[System.DateTime]">1990-04-01T00:00:00</d:BirthDate>
          </content>
        </entry>
        <entry m:type="EventsSample.Contact">
          <id>http://localhost:81/EventsSample/Contacts(124)</id>
          <title type="text"></title>
          <updated>2008-02-17T03:01:18Z</updated>
          <author>
            <name />
          </author>
          <link rel="edit" title="Contact" href="Contacts(124)" />
          <link rel="related" type="application/atom+xml;type=entry" 
title="BestFriend" href="Contacts(124)/BestFriend" />
          <content type="application/xml">
            <d:ContactID m:type="Int32">124</d:ContactID>
            <d:FirstName>John124</d:FirstName>
            <d:LastName>Doe124</d:LastName>
            <d:EmailAddress>[EMAIL PROTECTED]</d:EmailAddress>
            <d:Phone>123-456-124</d:Phone>
            <d:BirthDate 
m:type="Nullable`1[System.DateTime]">1990-05-01T00:00:00</d:BirthDate>
          </content>
        </entry>
        <!-- more entries for contacts that will be attendees in this party -->
      </feed>
    </m:inline>
  </link>
  <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>

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.

Feedback in general about this approach would be greatly appreciated.

(also posted this in the Astoria team blog)

Thanks
-pablo


Reply via email to