[rest-practices] Modelling membership

Bob McWhirter bmcwhirt at redhat.com
Tue May 4 17:00:06 UTC 2010


> So, by not having it toplevel, what we're thinking is equivalent to:
>
>  POST /users/1234/memberships
>
>  <membership>
>    <group id="4321"/>
>  </membership>

Generally speaking, I'd rather see hrefs instead of IDs:

   <group href="${url_to_group}"/>

I don't like this partial in-lined description of a <membership>  
resource, though, as then I have to keep up with user_id separately,  
it's not a part of the representation when fetched this way.  It's  
easier to code if I know I can resolve a URL to fetch a complete  
object, instead of having to considering it within some context.   
Particularly if we're ignoring URL structure and being HATEOASishy.

Depending on how "pure" you wanted to be, I might also do

<memberships>
   <membership href="${url1}"/>
   <membership href="${url2}"/>
</memberships>

And treat it as a collection of references.  This is what I mean by a  
"top-level" object.  One that is directly accessible with a discrete  
URL.  Here, though, we look at N+1 fetches, or some extra way to  
inline the results or fetch-all in a single operation.  (Both seem  
reasonable).

Versus a "value" object, which is purely embedded within another  
object, and not directly referenceable.

If you embed as a value, then I think you make sure it's not  
accessible, since it's more just an internal structure to the owning  
object.

In this case, perhaps embedded value is the way to go, in which case,  
purely the following, where the only href/URL points to the referenced  
group:

<memberships>
   <membership>
     <group href="${group_url}"/>
   </membership>
</membership>

Here, you don't have to repeat user_id, since context is implicit and  
mandatory, as we're embedded within the <user> object.  But then we're  
back to the race condition of multiple updates to a single url to add/ 
remove groups.  But that is orthogonol, and affects all fields on all  
resources.  We just happen to think it might be triggered on this one  
with high probability.

Perhaps time to think about optimistic locking, and a <version> serial  
number or timestamp on all resources, to allow the server to perform  
reasonable optimistic locking.

> We'll also make the membership list available read-only via the group:
>
>  GET /groups/4321
>
>  <group id="4321">
>    <name>foo</name>
>    ...
>    <memberships>
>      <link rel="membership" href="/users/1234/memberships/1111"/>
>      ...
>    </memberships>
>  </group>

Though, does a group have memberships?  Or does it have members?  A  
"membership" seems to be a management/structural object from User  
perspective, but not necessarily from the group perspective,  
especially if it's just referencing it in a read-only fashion.

I'd suggest:

<group>
   <name>foo</name>
   <members>
     <user href="${user_url1}"/>
     <user href="${user_url2}"/>
     ..
   </members>
</group>

In this case, we're reducing the number of fetches to obtain a list of  
all members of a group.  Having to bounce through a membership  
reference means 2N+1, where at least this way it's only N+1.  Same  
inline/fetch-all notes from above may then apply to optimise some more.

What an amazingly deep topic. :)

	-Bob










More information about the rest-practices mailing list