Are links embedded in hypermedia always immutable? What about the query string part of it? That question came up recently in our shop.
Now, I agree totally that the path part of the URI — that is, everything in front of the first “?” or “#” should be treated as an immutable, opaque string. That’s just saying that the server controls that part, and can change it at a moment’s notice. The client must be decoupled from the path of the URI. But the query string part of the URI is not so clear.
One point of view (from a really smart guy, so I respect his opinion a lot) was that URIs embedded in hypermedia are absolutely immutable, front to back. It’s the server’s responsibility to provide all the possible links a client could want, and the client just deferences those links as totally opaque strings.
For example, for paginating a resource that was a big list, someone stated that the server should send hypermedia that contained a full list of URIs to every page available. If that was 100 links, OK. If that was 1000 links, OK. But the client shouldn’t be able to pass a query string with an arbitrary offset and number of items to pull. Altering the query string constituted altering the URI, and was forbidden by the rules of REST.
(We were even threatened with losing our place at Level 3 of the Richardson Maturity Model of REST… but I’ll save that for another post.)
Unfortunately, that view of query strings doesn’t fit with how query strings are actually used in the most important hypermedia type of all, HTML.
HTML provides several ways to link to other hypertext pages:
- an <a href> with a static link,
- a <link> element with a static link
- and a <form> element that takes user input and constructs a query string, appended to a static link.
But HTML is still a hypermedia type.
In the REST world, the way to look at query string parameters is as qualifiers that change the scope of the underlying resource.
Search is a classic example, and one that is cited as problematic for REST. Because search requires free-form search criteria, and there is absolutely no way to present the client with a full list of searchable terms (well, I guess you could, but the list would be thousands and thousands of links long)… the client just has to pass the search criteria in the query string. So does that break REST’s hypermedia constraint?
But search is not a difficult case for REST — or even a special case — because the resource is EVERYTHING THAT WE’VE EVER INDEXED. That would be a lot of data to return at once. The search query string narrows the resource to just what we’re interested in. Taking the purist’s view, for a big resource, would simply be too expensive to anticipate every query the client might be interested in.
So “query” string is very intentionally named. There has to be a way to parameterize GET requests to the server, so the server knows what you really want.
Back to pagination: If the resource is a big list, it’s reasonable & consistent with hypermedia to apply a filter and say “Only show me the 10 items starting at item 110”. The larger resource is still the same, we’re just narrowing what we return.
That said, changing state with query string values is obviously way out of bounds!
Or another way to look at it is, URI definition allows for “matrix” parameters which are non-hierarchical name-value pairs that are in the “static” or “identifying” part of the URI. So why would we need a query string at all?
Ultimately, we’re going to have to get away from these stupid discussions about the limits that REST requires, and talk more about how to be smart with hypermedia.