[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