Simplified Discovery

The discovery mechanism currently within OpenSocial is based on XRD... I believe it's possible for us to simplify the discovery model by eliminating the need to use XRD and any XML format at all through the use of Link headers. 

There are several discovery use cases to consider:

  1. Discovering which services are exposed by an OpenSocial server in general. This is the case currently covered by Section 7 of the Core API specification. In this case, a client starts with the base URL of the server and uses it to retrieve a listing of the base endpoints for each of the exposed services.
  2. Discovering which services are available for a particular user. For instance, discovering the specific location of the users profile, any files they have available, whether they have a specific blog, etc... this case currently is not covered directly by the OS API... one essentially needs to grab the users profile and start from there.

In the current implementation, use case one is handled via XRD.. for example...

GET /api HTTP/1.1
Host: api.example.org
Accept: application/xrds+xml

Would return

HTTP/1.1 200 OK
Content-Type: application/xrds+xml


<XRDS xmlns="xri://$xrds">
   <XRD xmlns:simple="http://xrds-simple.net/core/1.0" xmlns="xri://$XRD*($v*2.0)" version="2.0">
       <Type>xri://$xrds*simple</Type>
       <Service>
         <Type>http://ns.opensocial.org/2008/opensocial/people</Type>
         <URI>http://api.example.org/people</URI>
       </Service>
       <Service>
         <Type>http://ns.opensocial.org/2008/opensocial/groups</Type>
         <URI>http://api.example.org/groups</URI>
       </Service>
       <Service>
         <Type>http://ns.opensocial.org/2008/opensocial/activities</Type>
         <URI>http://api.example.org/activities</URI>
       </Service>
       <Service>
         <Type>http://ns.opensocial.org//2008/opensocial/appData</Type>
         <URI>http://api.example.org/appData</URI>
       </Service>
       <Service>
         <Type>http://ns.opensocial.org/2008/opensocial/cache/invalidate</Type>
         <URI>http://api.example.org/cache/invalidate</URI>
       </Service>
       <Service>
         <Type>http://ns.opensocial.org/2008/opensocial/messages</Type>
         <URI>http://api.example.org/messages</URI>
       </Service>
       <Service>
          <Type>http://ns.opensocial.org/2008/opensocial/albums</Type>
          <URI>http://api.example.org/albums</URI>
       </Service>
       <Service>
          <Type>http://ns.opensocial.org/2008/opensocial/mediaItems</Type>
          <URI>http://api.example.org/mediaItems</URI>
       </Service>
   </XRD>
</XRDS>

The current OpenSocial specification goes on to state that if the response happens to include the non-standard X-XRDS-Location header, the client is supposed to follow the URL given within it's value to retrieve the XRDS document. This is way too overcomplicated...

Here's an alternative...

HEAD /api HTTP/1.1
Host: api.example.org

For which the response would be...

HTTP/1.1 200 OK
Link: <api/people>; rel="http://ns.opensocial.org/2008/opensocial/people",
  <api/groups>; rel="http://ns.opensocial.org/2008/opensocial/groups",
  <api/activities>; rel="http://ns.opensocial.org/2008/opensocial/activities",
  <api/appData>; rel="http://ns.opensocial.org/2008/opensocial/appData",
  <api/invalidate>; rel="http://ns.opensocial.org/2008/opensocial/invalidate",
  <api/messages>; rel="http://ns.opensocial.org/2008/opensocial/messages",
  <api/albums>; rel="http://ns.opensocial.org/2008/opensocial/albums",
  <api/mediaItems>; rel="http://ns.opensocial.org/2008/opensocial/mediaItems"

If the server wishes to redirect the client to a separate URL where a document describing the services available can be found, then it can use either a standard HTTP redirect or use a "describedBy" link in the header.. e.g.

HTTP/1.1 200 OK
Link: </api/discovery>; rel="describedBy"; type="application/json"

A key advantage of this approach is that the Link model translates easily into providing equivalent link details within (X)HTML, JSON, Atom, etc.

The profile discovery case would be nearly identical.. with each of the above link relations being added to the response for a users profile... for instance...

HEAD /api/people/@me HTTP/1.1
Host: api.example.org

Which would return something like...

HTTP/1.1 200 OK
Link: <api/people/@me>; rel="http://ns.opensocial.org/2008/opensocial/people",
  <api/activities/@me>; rel="http://ns.opensocial.org/2008/opensocial/activities",
  <api/appData/@me>; rel="http://ns.opensocial.org/2008/opensocial/appData",
  <api/messages/@me>; rel="http://ns.opensocial.org/2008/opensocial/messages",
  <api/albums/@me>; rel="http://ns.opensocial.org/2008/opensocial/albums",
  <api/mediaItems/@me>; rel="http://ns.opensocial.org/2008/opensocial/mediaItems"

Where each of the Links represent a service that is associated with this particular user.

If all you have is a users email address or basic account id and domain, we can use an evolution on the concepts pioneered by webfinger to perform a single profile discovery... for instance... given the email address "john@example.com", we can send a GET to http://example.com/.well-known/os/6b8d6e2e129a2f2ce3dc0a2e9ebdbdf1 (that's the md5 of 'john@example.com')...

GET /.well-known/os/6b8d6e2e129a2f2ce3dc0a2e9ebdbdf1 HTTP/1.1
Host: example.com

...which will direct our client to the appropriate profile URL...

HTTP/1.1 301 Moved Permanently
Location: /api/people/user12345678/@self

The server MAY choose to include all the discovery Link's in the response and could even choose to include a minimal view of the users profile.

These kinds of profile discovery requests can be protected by OAuth if necessary

This proposal eliminates the need to support XRDS, thereby eliminating the need for additional XML parsing, etc. A client and server implementation would need to have access to the HTTP response headers.