UserPreferences

PaceDecoupleDiscoverAndCreate


Abstract

Decouple resource discovery from resource creation and use links to conduct introspection.

Status

Open

Rationale

Creating and discovering resources are two distinct operations. The current protocol model conflates the two using the metaphor of a "collection". This is confusing as the behavior of implementations will often be quite different from that of a set of physical collections. Sometimes they will be more like views, gateways, etc. There is no denying that the collection is a useful and common pattern, but there is no reason to limit ourselves to it.

Perhaps even more importantly, the protocol is easier to explain in a more literal fashion. For instance, we can simply write about "a representation" rather than "a member representation".

The approach shown here also obviates the need for an introspection resource. Link elements (and content@src) are used to locate resources. Resources describe themselves and each other. An introspection resource can still exist, of course, but is just bonus.

This Pace still provides the machinery for introspection (as a process) to take place. If desired, a central manifest of endpoints can still be constructed but it is not needed.

An introspection document provides two things:

1. resource discovery (find "collections")

We can find resources by following links. The rel attribute is there to explain what kind of relationship exists between linked resources.

2. resource "capabilities" and other metadata

Where can I POST entries? Where can I POST media?

This is actually discovery; see above.

Proposal

Replace section 1 with:

1.  Introduction

  The Atom Publishing Protocol is an application-level protocol for
  publishing and editing Web resources using HTTP [RFC2616] and XML 1.0
  [W3C.REC-xml-20040204].  The protocol provides facilities for
  discovering, creating, reading, updating and deleting resources.

Remove from section 2:

  The Introspection Document allows the use of IRIs [RFC3987], as well
  as URIs [RFC3986].

Remove from section 3:

  collection - A resource that contains a set of member IRIs, as
  described in Section 8 of this specification.

  member - A resource whose IRI is listed in a collection.

  IRI template - A parameterized string that becomes a IRI when the
  parameters are filled in.  See Section 9.

  introspection document - A document that describes the location and
  capabilities of one or more collections.  See Section 7

Add to section 3:

  edit link - an Atom or HTML link element whose rel attribute value
  is 'edit' (See section 10.1)

  feed link - an Atom or HTML link element whose rel attribute value
  is 'feed' (See section 10.2)

  entrypost link - an Atom or HTML link element whose rel attribute
  value is 'entrypost (See section 10.3)

  mediapost link - an Atom or HTML link element whose rel attribute
  value is 'mediapost' (See section 10.4)

  workspace link - an Atom or HTML link element whose rel attribute
  value is 'workspace' (See section 10.5)

  editable representation - an editable representation is one that 
  actors MAY be allowed to edit.

Replace section 4 with:

4.  Protocol Model

  The Atom Publishing Protocol uses HTTP to edit resources on the web.
  Atom Feed Documents are used to list entry resources.  Atom Entry
  Documents are used to represent entry resources.  The APP uses these
  HTTP verbs:

  o  GET is used to retrieve a representation of a resource.

  o  POST is used to create a new resource.

  o  PUT is used to update a known resource.

  o  DELETE is used to remove a resource.

  The protocol allows editing of resources with representations of any
  media-type.

Replace section 5 with two sections:

5.  Discovering Resources

  Atom Feeds are used to discover the IRIs and other metadata of
  various resources.

  Client                          Server
    |                                |
    |  1.) GET                       |
    |------------------------------->|
    |                                |
    |  2.) 200 OK, Atom Feed Doc     |
    |<-------------------------------|
    |                                |

  1.  The client sends a GET request to a known IRI.

  2.  The server responds with an Atom Feed Document containing the
      IRIs and other metadata of various resources.

  The methods of identifying the IRIs of resources are detailed in
  sections 5.1 - 5.6.


5.1  Feeds

  The IRIs of Atom Feeds are found in the href attributes of feed links
  (see section 3).


5.1.1  Paging

  Feeds can be extremely large.  A naive client such as a web spider or
  web browser would be overwhelmed if the response to a GET contained
  every entry in the feed, and the server would waste large amounts of
  bandwidth and processing time on clients unable to handle the
  response.

  To cope with this, a feed can be represented by a series of Atom Feed
  Documents connected together using next links, prev links, start
  links and end links.


5.2  Entries

  The IRI of the source (editable) Atom Entry Document representation
  can be found in the href attribute of an edit link (see section 3).

  The IRIs of other (derived) representations can be found in the
  href attributes of alternate links.


5.3  Media

  The IRI of an editable representation that may be of any media type
  can be found in the src attribute of an atom content element.


5.4  Entry Post

  IRIs used to create resources by POSTing Atom Entry Documents can be
  found in the href attributes of entrypost links (see section 3).


5.5  Media Post

  IRIs used to create resources by POSTing representations of any media
  type can be found in the href attributes of mediapost links (see
  section 3).


5.6  Workspaces

  Any resource with links that can be used to discover the IRIs 
  of Atom resources can be considered to be a "workspace". The IRIs of 
  workspace resources can be found in the href attributes of workspace 
  links (see section 3). Typically workspace resources will be HTML 
  documents or empty Atom Feeds with links to Atom resources. The purpose 
  of such documents is simply to organize the discovery of Atom resources.

6.  Protocol Operations

6.1  Creating a Resource

  Client                                   Server
    |                                           |
    |  1.) POST                                 |
    |------------------------------------------>|
    |                                           |
    |  2.) 201 Created                          |
    |<------------------------------------------|
    |                                           |

  1.  The client POSTs a representation.

  2.  If the resource was created successfully the server responds with
      a status code of 201 and a Location: header that contains the IRI
      of the newly created resource.


6.1.1  Creating a Resource via Entry Post

  If the representation was POSTed to an entry post (see section 5.1.4)
  the IRI returned is that of the editable Atom Entry Document.


6.1.2  Creating a Resource via Media Post

  If the representation was POSTed to a media post (see section 5.1.5)
  the IRI returned will be that of a representation of the same type
  POSTed.


6.2  Reading a Resource

  Client                                   Server
    |                                           |
    |  1.) GET                                  |
    |------------------------------------------>|
    |                                           |
    |  2.) Representation                       |
    |<------------------------------------------|
    |                                           |

  1.  The client sends a GET request to a known IRI to retrieve
      a representation of a resource.

  2.  The server responds with the representation of the resource.


6.3  Updating a Resource

  Client                                     Server
    |                                           |
    |  1.) PUT                                  |
    |------------------------------------------>|
    |                                           |
    |  2.) 200 OK                               |
    |<------------------------------------------|

  1.  The client PUTs an updated representation to a known IRI.

  2.  Upon a successful update of the resource the server responds with
      a status code of 200.


6.4  Deleting a Resource

  Client                                     Server
    |                                           |
    |  1.) DELETE                               |
    |------------------------------------------>|
    |                                           |
    |  2.) 200 Ok                               |
    |<------------------------------------------|
    |                                           |

  1.  The client sends a DELETE request to a known IRI.

  2.  Upon the successful deletion of the resource the server responds
      with a status code of 200.



6.5  Success and Failure

  The Atom Protocol uses HTTP status codes to signal the results of
  protocol operations.  Status codes of the form 2xx signal that a
  request was successful.  HTTP status codes of the form 4xx or 5xx
  signal that an error has occurred.  Consult the HTTP specification
  [RFC2616] for the definitions of HTTP status codes.

Remove sections 7, 8, and 9

Replace the text at the beginning of section 10:

10.  Atom Entry Extensions

  This specification adds four new values to the Registry of Link
  Relations and adds a new element to Atom Entries called "app:control"
  for controlling publishing.

Replace section 10.1

10.1  The 'edit' Link Relation

  This specification adds the value "edit" to the Registry of Link
  Relations.  The value of "edit" signifies that the IRI in the value
  of the href attribute is the IRI of the resource, and is intended to
  be used to update and delete resources as described in section 6.


Add the following subsection to section 10:

10.2  The 'feed' Link Relation

  This specification adds the value "feed" to the Registry of Link
  Relations.  The value of "feed" signifies that the IRI in the value
  of the href attribute is the IRI of a feed resource, and is intended
  to be used to discover resources as described section 5.


10.3  The 'entrypost' Link Relation

  This specification adds the value "entrypost" to the Registry of Link
  Relations.  The value of "entrypost" signifies that the IRI in the
  value of the href attribute is the IRI of a service resource, which is
  intended to accept POST requests containing entry representations for
  the purpose of creating resources as described section 6.1.1.


10.4  The 'mediapost' Link Relation

  This specification adds the value "mediapost" to the Registry of Link
  Relations.  The value of "mediapost" signifies that the IRI in the
  value of the href attribute is the IRI of a service resource, which is
  intended to accept POST requests containing representations of various
  types for the purpose of creating resources as described section 6.1.1.


10.5 The 'workspace' Link Relation

  This specification adds the value "workspace" to the Registry of Link
  Relations.  The value of "workspace" signifies that the IRI in the 
  value of the href attribute is the IRI of a resource, which is intended 
  for use in discovering other Atom resources.


Examples

Workspaces

Lets say that you have two blogs: one about motorcycles and one about gardening.

Lets say you would like to lay out interface in a pattern of workspaces containing collections such that your service looks like this:

-spaces
  |
  -motorcycles
  |  |
  |  -entries
  |  -media
  -gardening
     |
     -entries
     -media

You start by pointing your client at /spaces

GET /spaces/index.html

<html>
   <head>
      <link rel="workspace" title="Motorcycles Blog" href="/motorcycles/index.html"/>
      <link rel="workspace" title="Gardening Blog" href="/gardening/index.html"/>
      ...
   </head>
   ...
</html>

GET /motorcycles/index.html

<html>
   <head>
      <link rel="alternate" title="Motorcycles Feed" href="/motorcycles/entries"/>
      <link rel="feed" title="Entries Feed" href="/motorcycles/entries"/>
      <link rel="entrypost" title="Entries POST" href="/motorcycles/entries"/>
      <link rel="feed" title="Media Feed" href="/motorcycles/media"/>
      <link rel="mediapost" title="Media POST" href="/motorcycles/media"/>
      ...
   </head>
   ...
</html>

GET /motorcycles/entries

<feed>
  <link rel="self" title="Motorcycles Entries" href="/motorcycles/entries"/>
  <link rel="feed" title="Motorcycles Feed" href="/motorcycles/entries"/>
  <link rel="entrypost" title="Motorcycles POST" href="/motorcycles/entries"/>
  <link rel="mediapost" title="Media POST" href="/motorcycles/media"/>
  <link rel="workspace" title="Motorcycles" href="/motorcycles"/>
  ...
</feed>

You could point your client directly at one of these:

Then go ahead and POST an entry with a pic of your cat sitting on your new bike.

If you point your client at spaces you have to follow one link.

Nested Collectons

The following is taken from an email exchange between myself (LukeArno) and JamesSnell:

So I have the following:

I am going to choose to treat '/entries' as the 'root' collection. I am treating everything as a collection except for the media. Their are two media feeds that share a gateway. If you POST an image file it ends up in the Photo Album feed. Otherwise it ends up in various.

I am implementing this with a "default collection" pattern a la Robert S. In other words, this is nested collections without workspaces. If you would like to see a "workspaces" style layout of collections or one gateway and many feeds, see above.

- entries
   - photos
   - stories
   - various
   - bookmarks  

GET /entries:

<feed>
  <link rel="self"
           title="Entries"
           href="/entries"/>
  <link rel="entrypost"
           title="POST Entries"
           href="/entries"/>
  <link rel="mediapost"
           title="POST Media"
           href="/mediapost"/>
  <link rel="feed"
           title="Stories"
           href="/stories"/>
  <link rel="feed"
           title="Photoalbum"
           href="/photos"/>
  <link rel="feed"
           title="Various"
           href="/various"/>
  <link rel="feed"
           title="Bookmarks"
           href="/bookmarks"/>
  ...
</feed>

GET /stories:

<feed>
  <link rel="self"
           title="Stories"
           href="/stories"/>
  <link rel="entrypost"
           title="POST Stories"
           href="/stories"/>
  <link rel="mediapost"
           title="POST Media"
           href="/mediapost"/>
  ...
</feed>

GET /photos:

<feed>
  <link rel="self"
           title="Photoalbum"
           href="/photos"/>
  <link rel="mediapost"
           title="POST Media"
           href="/mediapost"/>
  ...
</feed>

GET /various:

<feed>
  <link rel="self"
           title="Various"
           href="/various"/>
  <link rel="mediapost"
           title="POST Media"
           href="/mediapost"/>
  ...
</feed>

GET /bookmarks:

<feed>
  <link rel="self"
           title="Bookmarks"
           href="/bookmarks"/>
  <link rel="entrypost"
           title="POST Bookmarks"
           href="/bookmarks"/>
  ...
</feed>

GET /index.html:

<html>
  <head>
     <link rel="feed" title="Entries" href="/entries"/>
     ...
  </head>
  ...
</html>

Point your client at / and off you go.

Multiple Blogs

In some cases a service provider may want to expose multiple blogs available through one account.

One way to do this would be to provide a common "root" feed that links to the resources of multiple services. A service may not want to provide a root feed but still enable the user to point the client at one IRI:

Nested collections:

GET /myaccounts/index.html

<html>
   <head>
      <link rel="feed" title="Blog One" href="/blogone/entries"/>
      <link rel="feed" title="Blog Two" href="/blogtwo/entries"/>
      <link rel="feed" title="Blog Three" href="/blogthree/entries"/>
      ...
   </head>
   ...
</html>

Others may want to use a "workspaces" pattern:

GET /myaccounts/index.html

<html>
   <head>
      <link rel="workspace" title="Blog One" href="/blogone/index.html"/>
      <link rel="workspace" title="Blog Two" href="/blogtwo/index.html"/>
      <link rel="workspace" title="Blog Three" href="/blogthree/index.html"/>
      ...
   </head>
   ...
</html>

Librarian

Lets say you have a system where entries are arranged by category and there is a librarian who is responsible for categorization. You POST entries to some common gateway and the librarian puts them in categories which lands them in the appropriate feed.

To begin you are reading the "Birding" (bird watching) feed and you decide to POST an entry:

GET /birding

<feed>
  <link rel="entrypost" title="New Entry" href="/new-entry"/>
  ...
</feed>

You client puts together the entry with a category of "birds". That was the wrong name, but that is why the librarian has to approve it. You POST the entry to /new-entries. You entry is flagged with a <x:needs-review/> extension and appears in a feed for the librarian at /needs-review.

GET /needs-review

<feed>
  ...
  <entry>
    <category term="birds" label="Birds"/>
    <link rel="edit" href="/new-entries/346"/>
    <x:needs-review/>
    ...
  </entry>
</feed>

}}

The librarian sees that you have mis-categorized you entry but
that it is otherwise valid. Librarian edits the entry:

GET /new-entries/346 

{{{

<entry>
  <category term="birds" label="Birds"/>
  <link rel="edit" href="/new-entries/346"/>
  <x:needs-review/>
  ...
</entry>

Librarian changes the category to "birding", adds the category "nature", removes <x:needs-review/> and PUTs it back.

The entry no longer appears in the /nees-review feed but now appears in /birding and in /nature.

Entries Can Accept Comments

Clients (including aggregators) need to know where to post comments. Since feeds, entries, and entry and media POST services are fully independent of each other, this is no problem. For instance, if I wanted to be clever I could accept entries POSTed to my entry as comments on that entry. So if I have:

GET /blog/archive/2005/11/13/1

<entry>
   <link rel="entrypost"
         title="POST a Comment on this Entry"
         href="/blog/archive/2005/11/13/1"/>
   ...
</entry>

Anything POSTed to one of my permalinks in this case would have a link[@rel="about" and href="my permalink"] or an appropriate extension added to it, identifying it as a comment and what on.

If I wanted to expose a comment feed for that entry I could add another link:

GET /blog/archive/2005/11/13/1

<entry>
   <link rel="entrypost"
         title="POST a Comment on this Entry"
         href="/blog/archive/2005/11/13/1"/>
   <link rel="feed"
         title="Comments Feed for this Entry"
         href="/blog/archive/2005/11/13/1/comments"/>
   ...
</entry>

Private Public

There is no reason why you can't have private and public interfaces in any arrangement that you want. Lets take a blog with an address book, drafts, published, and plans for world domination on the private side and entries (a read only view of published) and comments on the public side.

The private side will all be under /app and the public side will all be under /blog to make securing things at a low level easy.

All these feeds are discovered by the blogger at /app/index.html

GET /app/index.html

<html>
   <head>
      <link rel="feed" title="Address Book" href="/app/people"/>
      <link rel="feed" title="Drafts" href="/app/drafts"/>
      <link rel="feed" title="Published" href="/app/"/>
      <link rel="feed" title="Plans for World Domination" href="/app/plots"/>
      <link rel="feed" title="Blog Entries" href="/blog/entries"/>
      <link rel="feed" title="Comments" href="/blog/comments"/>
      ...
   </head>
   ...
</html>

All entries in feeds under /app have an edit link.

GET /app/people

<feed>
  <link rel="entrypost"
           title="POST hCards"
           href="/people"/>
  ...
</feed>

GET /app/drafts

<feed>
  <link rel="entrypost"
           title="POST Drafts"
           href="/drafts"/>
  ...
</feed>

Entries are moved from drafts to published. Anything in published appears in /blog/entries (see below) as well

GET /app/published

<feed>
  <link rel="entrypost"
           title="POST Entries to be Publicly"
           href="/published"/>
  ...
</feed>

GET /app/plots

<feed>
  <link rel="entrypost"
           title="POST Plans for World Domination"
           href="/plots"/>
  ...
</feed>

The public HTML interface only exposes the appropriate endpoints:

GET /blog/index.html

<html>
   <head>
      <link rel="feed" title="Blog Entries" href="/blog/entries"/>
      <link rel="feed" title="Comments" href="/blog/comments"/>
      <link rel="entrypost" title="POST Comments" href="/comments"/>
      ...
   </head>
   ...
</html>

Note that entries that appear in /blog/entries have no edit link and the only entrypost is for comments:

GET /blog/entries

<feed>
  <link rel="entrypost"
           title="POST Comments"
           href="/comments"/>
  ...
</feed>

Entries in /blog/comments have no edit link but the comments endpoint does accept POST.

GET /blog/comments

<feed>
  <link rel="entrypost"
           title="POST Comments"
           href="/comments"/>
  ...
</feed>

Obviously this could all have been arranged an many many other ways.

Cell Phone Manifest

A simple manifest to bootstrap a cell phone client:

GET /cell

<html>
 <head>
  <title>My Blog</title>
  <link rel="feed" title="Entries" href="/entries"/>
  <link rel="entrypost" title="POST Entries" href="/entries"/>
  <link rel="feed" title="Media" href="/media"/>
  <link rel="mediapost" title="POST Media" href="/media" type="*/*"/>
 </head>
 <body>
  <h1>Cell Phone Loader</h1>
  <p>
     Point your cell phone client here find
     all your endpoints in 1 round-trip.
  </p>
 </body>
</html>

Extensions

Extended metadata can be embeded in links as attributes or elements:

<feed>
  <link rel="entrypost" title="POST Entries" href="/entries">
    <accepted-type version="x.x">hCard</accpeted-type>
  </link>
  ...
</feed>

Extensions and Workspaces

XHTML link elements do not allow any child elements so if you have a need for extension elements in workspace links you will need to use another format, such as an Atom Feed Document:

GET /index.html

<html>
 <head>
  <title>My Blog</title>
  <link rel="workspace" title="Workspace" href="/workspace"/>
  ...
 </head>
 ...
</html>

GET /workspace

<feed>
  <link rel="entrypost" title="POST Entries" href="/entries">
    <accepted-type version="x.x">hCard</accpeted-type>
  </link>
  ...
</feed>

This will probably not be a concern in most cases.

Lazy Loading

"But how in the world does my client fill out it's purdy tree diagram of folders in the left panel?"

1. Retrieve "root" feed and display with plus sign

+ root feed

2. Click on plus sign retrieve feeds linked from root

- root feed
  + posts feed  [ post entries]  [ post media ]
  + all comments feed
  + all media  [ post media ]

3. Click on "posts feed" plus sign to expand that

- root feed
  - posts feed   [ post entries]  [ post media ]
     + category a  [ post cat a entries ]
     - category b  [ post cat a entries ]
     + category c  [ post cat a entries ]
  + all comments feed
  + all media  [ post media ]

Heck, you could even have expandable entries in your top right entry listing panel for entries that have comment feeds or what have you. You could right click an entry and fire off a comment if an entry has an "entrypost" link (probably titled with "POST a comment" or some such.

You can keep track to avoid circular references quite easily. That is the only problem I could think of.

Categories Breakdown

What happens if you have a bunch of category feeds and you don't want to clog the main feed with links. In fact, lets assume that you have a really gargantuan set of categories. How do you break things down in to some neat and tidy arrangement?

Here is one way:

GET /mainfeed

<feed>
  <link rel="workspace" title="Categories" href="/categories"/>
  ...
</feed>

GET /categories

<html>
  <head>
    <link rel="workspace" title="A-F" href="/categories/A-F"/>
    <link rel="workspace" title="G-L" href="categories/G-L"/>
    ...
  </head>
  ...
</html>

GET /categories/A-F

<html>
  <head>
    <link rel="feed" title="aardvark" href="/categories/A-F/aardvark"/>
    <link rel="feed" title="abacus" href="/categories/A-F/abacus"/>
    ...
  </head>
  ...
</html>

Cat Picture (Section 11)

11.  Example

   This is an example of a client creating a new entry with an image.
   The client has an image to publish and an entry that includes an HTML
   'img' element that uses that image.  In this scenario we consider a
   client that has the IRIs of both an entry post and a media post. (see
   section 5) The IRI of the entry post is:

   http://example.net/blog/edit/

   The IRI of the media post is:

   http://example.net/binary/edit

   First the client creates a new image resource by POSTing the image to
   the IRI of the media post.

   PO ST /binary/edit/ HTTP/1.1
   Host: example.net
   Us er-Agent: Thingio/1.0
   Con tent-Type: image/png
   Con tent-Length: nnnn
   Title: A picture of the beach

   ...binary data...

   The resource is created and an HTTP status code of 201 is returned.

   HTTP/1.1 201 Created
   Date: Fri, 25 Mar 2005 17:17:11 GMT
   Con tent-Length: nnnn
   Con tent-Type: application/atom+xml
   Loc ation: http://example.net/binary/edit/b/129.png

   <?xml version="1.0" encoding="utf-8"?>
   <entry xmlns="http://www.w3.org/2005/Atom";>
       <title>A picture of the beach.</title>
       <link rel="edit"
           href="http://example.net/binary/edit/b/129.png"/>
       <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-568596895695</id>
       <updated>2005-09-02T10:30:00Z</updated>
       <summary>Waves</summary>
       <content type="image/png"
           src="http://example.net/binary/readonly/129.png"/>
   </entry>


   The client then POSTs the Atom Entry that refers to the newly created
   image resource.  Note that the client takes the IRI
   http://example.net/binary/readonly/129.png and uses it in the 'img'
   element in the Entry content:

   PO ST  /blog/edit/ HTTP/1.1
   Host: example.net
   Us er-Agent: Thingio/1.0
   Con tent-Type: application/atom+xml
   Con tent-Length: nnnn

   <?xml version="1.0" encoding="utf-8"?>
   <entry xmlns="http://www.w3.org/2005/Atom";>
       <title>What I did on my summer vacation</title>
       <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-568599874695</id>
       <updated>2005-09-02T10:30:00Z</updated>
       <summary>Beach!</summary>
       <content type="xhtml" xml:lang="en">
           <div xmlns="http://www.w3.org/1999/xhtml";>
               <p>We went to the beach for summer vacation.
                   Here is a picture of the waves rolling in:
                   <img
                       src="http://example.net/binary/readonly/129.png";
                       alt="A picture of the beach."
                       />
               </p>
           </div>
       </content>
   </entry>


References

http://www.sixapart.com/pronet/docs/typepad_atom_api#1._Listing_the_User's_Weblogs http://lukearno.com/projects/atom-pub/app-model.html

Impacts

draft06

Notes


CategoryProposals