Sumana wants me to post some analyses of web services and talk about how they are or could be made more RESTful. Alex
Barnett wants me to look at Microsoft's Astoria project (so does
Microsoft, apparently, since they named it after where I live). I love
it when a plan comes together. Here is some free consulting for
Microsoft, based entirely on my readings of white papers ("overview" and
I wrote this entry by going through the two white papers and trying
to discern what resources the system exposed, what parts of the
uniform interface they support, what representations are served and
accepted, and how resources link to each other. This is the same
approach I took when analysing the Atom Publishing Protocol for
RWS. I'm pretty sure I got everything right, but I'm not totally sure about the association resources. I've presented my findings in a form much like the one I'd like to see if I was trying to figure out how a RESTful web service worked. I hope this helps.
Astoria is a framework for a certain class of web services: those
that expose access to tables and rows in a database. In this regard
it's similar to ActiveResource. The resources exposed might not
correspond exactly to the underlying database objects, but they will
look like database tables and there will be some kind of mapping to a
The "overview" whitepaper starts out covering some of the ground
covered in RWS chapter 11. It points out that Ajax applications
have a different architecture than traditional web
applications. They're GUI applications where the GUI events are
handled by an invisible web service client. Astoria wants to provide
the services those clients will access.
Astoria "uses URIs to point to pieces of data"
(ie. resources). Astoria's "data services" are "surfaced to the web as
a REST-style resource collection that is addressable with URIs and
that agents can interact with using the usual HTTP verbs such as GET,
POST or DELETE." So far so good. They talk the talk.
Meet the Resources
An Astoria service defines six basic kinds of resources. A lot of them correspond directly to a resource type in ActiveResource
and/or the Atom Publishing Protocol. This makes sense because all three are solving similar problems: exposing collections and the objects in the collections.
- The "Entity-set list" resource, located at the service root
(/data.svc, for example.) This is not explicitly called out,
but it has a URI and responds to GET, so it's a resource. This is a
simple list of the available entity-sets (see below). It's analagous
to the APP service documents.
- "Entity-set" resources. These correspond to a table in a
database. ActiveResource has these too; they're analagous to APP's
collections. An entity-set is identified like so: /data.svc/Customers. Notably, this is where
pagination and "order by" are supported.
- There are virtual entity-sets which correspond to a query on a
database table: /data.svc/Customers[Valuation gteq
5000000]. This is analagous to the GData extensions to the APP
that add query capability to APP collections.
- "Entity" resources. These correspond to
rows in a database table. ActiveResource has these too, and they're
analagous to APP's members.
A entity is identified with its collection name and then some kind
of unique index: maybe /data.svc/Customers or
- There are scoped entity-sets which are associated with some
entity. /data.svc/Customers[ALFKI]/Orders shows all the
"order" entities associated with a particular "customer" entity.
/data.svc/Territories/Employees shows all the
"employee" entities associated with a particular "territory" entity.
- Finally, for many-to-many relationships there are separate
resources. /data.svc/Territories/Employees shows
the relationship between territory 99999 and employee 3. Presumably it's also available as /data.svc/Employees/Territories.
(Note: the white papers also talk about a non-resource
"association" that's part of the state of an entity. It's a link from
one entity to another, as part of a relationship that's not
many-to-many. For instance, every order associated with
Customers[ALFKI] will contain a link in its representation to
Customers[ALFKI]. These associations are not
resources, because they don't have their own URIs; they only show up
in representations of entities. When I say "association" I'm talking
about association resources.)
The uniform interface
What do other frameworks do? The APP and Rails define GET and POST
on a "collection" resource; and GET, PUT, and DELETE on a "member"
resource. The APP defines GET on a service document. Where Astoria has
similar resources, it exposes the same interface. The only part that's
difficult to explain is the difference between POST on a regular
collection and POST on a scoped collection.
The "overview" white paper has a confusing paragraph about
Astoria's use of the uniform interface (the one that begins "For URIs
that represent a specific entity...") which is either wrong or very
poorly worded: I read it as saying that entities respond to POST,
which doesn't make sense. Here's what I got from the "using" white
paper, in convenient table form:
||X (Create a new entity)
||X (Create an association between two entities)
I'll just explain "Create an association between two entities,"
shall I? Here's a scoped entity-set:
/data.svc/Territories/Employees. It's a collection of
employees, scoped to a particular territory. There's a many-to-many
relationship between territories and employees (at least according to
the whitepaper). If I want to associate an existing employee with
territory 99999, I POST a representation of the employee to the scoped
entity-set. (The representation just contains the employee's database
ID.) A new resource is created at a URI like
/data.svc/Territories/Employees: it's the
relationship between territory 99999 and employee 3.
"Currently Astoria can represent data in plain XML, JSON
Representations are selected through content negotiation or through a
query string parameter.
Incoming representations have the same format as outgoing
So far, so good. But now Astoria must truly pass through the
RESTful crucible. How well does it use hypermedia? Pretty well,
actually. The "site map" resource links to all the top-level
entity-sets. Entity-sets link to entities and to appropriate entity-sets scoped to each entity. A sample XML representation of
http://myserver/data.svc/Customers gives the URI to each
customer in the list, and an "orders" link to each customer's
orders. This is excellent, much better than ActiveResource.
This lame diagram shows my interpretation of how Astoria resources
link to each other. There are two minor missing pieces. First, there's
no way to get to a virtual entity-set without constructing the URI
manually. This is understandable because those URIs can be about as
complicated as SQL expressions. You can't design an HTML 4 form that
can generate all of them. You could support a simplified version with
a HTML 5 or WADL form. I'm also thinking of a series of resources that
work like Bugzilla's advanced query builder to support every kind of
query building. It might not be worth it.
Second, I get the impression that a scoped entity-set links to the
entities inside the set, but not to the corresponding association
resources. That would mean if you want to DELETE an association, you
need to construct the URI yourself. This is a guess because I didn't
see a representation of a scoped collection.
As with Yahoo!'s web services, Astoria's JSON representations can
be wrapped in a callback function that calls your code. This lets you
from a foreign web service in your Ajax application. (The "using"
white paper calls this JSONP, for JSON with Padding.)
The "overview" whitepaper says the pagination variables are
skip and take, but the "using" whitepaper says
they're skip and top. Whitepaper bug!
You can create "service operations", which are arbitrary .NET
methods exposed through GET requests. The example given is a custom
query, but in practice this feature will encourage a REST-RPC style of
programming. However, "[i]n the future attributes will be extended so
that the specific HTTP method can be controlled." And the hooks for
error checking and triggers are exposed in a way I think will promote
Sam's favorite section: what about caching and ETags? "Astoria
services also leverage other aspects such as the well-established HTTP
caching infrastructure. Data services can be configured to set various
caching-related HTTP headers to cache at the web server, client agent,
or intermediate agents such as proxies." It sounds like caching works
automatically--with a tie-in to the database engine? No mention of
ETags in either white paper.
"Microsoft may have patents, patent applications, trademarks,
copyrights, or other intellectual property rights covering subject
matter in this document." I sure hope not.
Astoria services are in fact RESTful and resource-oriented. They're
very similar to APP services, though not so much that the APP is
obviously a better base. The main thing I'd worry about is the
tendency for programmers to use the hooks for writing RPC-style
code. I'd head this off at the pass with the promised support for
service operations triggered by other HTTP methods, some RESTful
examples, and maybe a bit of theory. But I don't know the best way to herd