Nesting resources inside XML or JSON is sort of easy and obvious in REST. But what about broader relationships, like many-to-many relationships, or relationships between resources on different systems?
It’s perfectly fine to have a RESTful service hold those relationships, and give a client the ability to define and control them.
The big benefit of systems based on addressible resources is that the resources are identified by portable URIs. The big payoff is that, unlike database primary keys, the identifiers are usable in a much broader context than just that system itself. In most cases, those URIs are, in fact, URLs. But since they are addressable, we’re not limited by things like PK values or names that only our system understands. We can share those identifiers between disparate systems.
As long as the client treats URIs as opaque strings, it’s OK to send in “linking” or “association” objects. For example, PUT a resource that contains a list of items with a from URI and a to URI. But, as usual, you wouldn’t want the client building strings to do that.
Here are some considerations.
- The bitter pill is that REST by design doesn’t support relational integrity. So if you build a big graph of objects related by their URI, it’s possible that a lot of those URIs point to data that’s been deleted. 404 is always an option in REST (or HTTP).
- The other thing is that the URIs in your relations might go stale. So where it makes sense, the server might want to convert the URIs to more permanent internal identifiers so that the server doesn’t get coupled to those specific URIs.
- On the other hand, see point (1)
- Remember that HTTP itself has protocols, like the 301 response, for notifying a client when a resource has moved. So use the mechanisms that HTTP provides to help manage relational integrity.
For example, let’s say the URIs all look like “http://woopa.com/rest/v1/some/thing”, but Woopa Inc. gets bought by Wowee Corp. So of course they change their public domain, and URIs, to “http://wowee.com/rest/v1/some/thing”. But if they saved their relations as “http://woopa.com”, then they are tightly coupled to the specifics of the URI.
Here’s the thing that makes it all a little more wacky. We’re used to URIs that are also URLs. But the URI spec is *very* broad. The U in URI just stands for “Uniform”. So:
- this is a URI: http://woo/baa/rest/v1/zing
- this is a URI: urn:woo:baa:zing
Or if you permit relative URIs:
- this is a URI: catinthehat
- this is a URI: 1
So the URIs that the client communicates to the server don’t have to be full-blown URLs or generic URIs. They can also be short identifiers.
So, as an example, a client may tell the server to form a relationship between the items identified in the tuple [“bat”,”guano”]. But the client, and even the server, might not even know if “bat” or “guano” is really a name. The important thing is that the system that uses that relationship must understand the context around the URIs and be able to dereference them.
Additionally, the client, and possibly the server, might not actually interact with the resources they’re identifying. The client may have found the URIs through GETing other resources. Or it may come from user input. The server containing the relationship may only manage the relationship, and the actual resource might live on another server. Any system that has a field called “such-and-such-URL” is a good example of this.
So the nice thing about systems of addressable resources is that relationships across a broad range of resources is possible. Just watch out for the quirks that go along with disparate systems, and be aware of what you can do to manage and look up URIs.