Pretty URLs vs Query Strings

268 views
Skip to first unread message

Jay C

unread,
Feb 16, 2016, 10:29:13 AM2/16/16
to API Craft
What reasons are there to prefer pretty urls (e.g.) /users/1/messages vs query strings (e.g.) messages?users=1

I am working with someone who believes all resources should be at the 1st level and all other data is placed in the query string (aka no pretty urls).  He believes that pretty urls are harder to implement and provide no benefit.

Ruben Verborgh

unread,
Feb 16, 2016, 11:11:32 AM2/16/16
to api-...@googlegroups.com
Hi,

> What reasons are there to prefer pretty urls (e.g.) /users/1/messages vs query strings (e.g.) messages?users=1

Strictly speaking, none. URIs are just opaque identifiers.

Practically speaking:
– URIs with a query string can be generated by an HTML <form>
– URIs with a query string might have caching/prefetching differences not under your control

This second point has to do with the fact that in the past, non-safe actions were sometimes wrapped in query strings (e.g., /users?action=delete&id=1).

> I am working with someone who believes all resources should be at the 1st level and all other data is placed in the query string (aka no pretty urls). He believes that pretty urls are harder to implement and provide no benefit.

“Harder to implement” depends on the framework and is not a general truth. (And if the framework makes something like that hard to implement, I have my doubts about that framework.)

"No benefit" is almost right.

That said, talking about a long-term URI strategy, query-string-based URIs are often (but not always) an artefact of process-based thinking instead of resource-based thinking. Processes change more frequently than resource identity, so designing URIs based on resources can be important to guarantee longterm stability.

Best,

Ruben

Darrel Miller

unread,
Feb 16, 2016, 2:06:36 PM2/16/16
to api-...@googlegroups.com
I'd like to echo what Ruben has said with the addition of a couple of things.

Query string parameters are also part of the resource identifier. Therefore /customer?id=1 and /customer?id=2 are two different resources.

Generally, path parameters are use when there is a natural hierarchy of resources

/{country}/{region}/{city}/pointofinterest

And query parameters are used where there isn't a hierarchy

/pointofinterest{?lat,long}

Darrel
--
You received this message because you are subscribed to the Google Groups "API Craft" group.
To unsubscribe from this group and stop receiving emails from it, send an email to api-craft+...@googlegroups.com.
Visit this group at https://groups.google.com/group/api-craft.
For more options, visit https://groups.google.com/d/optout.

Paul Mansour

unread,
Feb 17, 2016, 2:15:22 PM2/17/16
to API Craft
On Tuesday, February 16, 2016 at 11:11:32 AM UTC-5, Ruben Verborgh wrote:


Strictly speaking, none. URIs are just opaque identifiers.

Hi all. Been lurking on this group for awhile, and find the the discussions quite useful.

I notice that the opaqueness of URIs appears to be a popular idea. Is this a new turn of events? Roy Fielding has, I think,  emphatically stated in the past that URIs are not opaque, and that well designed URIs are a good thing, will make an API more useful, and can provide more entry points. In addition, Tim Berners-Lee has noted that the query string portion of the URI is certainly not opaque and that furthermore, the path portion, separated by slashes, was no accident of design.  The hierarchy is important. And URIs must be carefully parsed in order to determine its component parts, which by definition appears to imply they are not opaque.

I also note that Leonard Richardson also make the case for non-opaque UR!s in his book RESTFul Web Services.

Has there been a general change of thought in the REST community on this?  While REST and HATEOAS imply that resources should be discoverable, does it follow they should be obscure? I have even seen articles arguing for purposefully obscure URIs.

Or am I misinterpreting what is meant by opaque? I assume it to be similar to the property of an ETag.

 

Ryan Hiebert

unread,
Feb 17, 2016, 2:43:34 PM2/17/16
to api-...@googlegroups.com
On Feb 17, 2016, at 1:15 PM, Paul Mansour <pa...@carlislegroup.com> wrote:

On Tuesday, February 16, 2016 at 11:11:32 AM UTC-5, Ruben Verborgh wrote:


Strictly speaking, none. URIs are just opaque identifiers. 

I notice that the opaqueness of URIs appears to be a popular idea. Is this a new turn of events? Roy Fielding has, I think,  emphatically stated in the past that URIs are not opaque, and that well designed URIs are a good thing, will make an API more useful, and can provide more entry points. In addition, Tim Berners-Lee has noted that the query string portion of the URI is certainly not opaque and that furthermore, the path portion, separated by slashes, was no accident of design.  The hierarchy is important. And URIs must be carefully parsed in order to determine its component parts, which by definition appears to imply they are not opaque.

I also note that Leonard Richardson also make the case for non-opaque UR!s in his book RESTFul Web Services.

Has there been a general change of thought in the REST community on this?  While REST and HATEOAS imply that resources should be discoverable, does it follow they should be obscure? I have even seen articles arguing for purposefully obscure URIs.

Or am I misinterpreting what is meant by opaque? I assume it to be similar to the property of an ETag.

They are actually two different concerns, with different audiences. I believe that both are simultaneously correct.

Semantic URLs are great for the people writing the APIs, and logging and debugging them. It really helps to have semantics of a URL be obvious to the implementer. This may have the side-effect of it also being obvious to an end-user, but it's not the purpose.

The opacity of a URL refers to what a client should need to know about a URL to use it. In that case, they shouldn't need to know anything at all about the structure of the URL. There should instead be other metadata that tells them how and what a link is, such as link relations and forms.

Consider a common site. A user will only know, most of the time, to browse to the root URL. From there, they log in (fill in a form), browse around the site (follow links), but they virtually never look at the URL again, because it just doesn't matter to them. The semantics are still often there in the URL, because it's helpful, it's just not, in any way, a part of the end-user interface.

Ruben Verborgh

unread,
Feb 17, 2016, 2:48:08 PM2/17/16
to api-...@googlegroups.com
Hi Paul,

> Roy Fielding has, I think, emphatically stated in the past that URIs are not opaque, and that well designed URIs are a good thing

Note that that these points do not necessarily contradict each other.
A URI space should be well-designed.

The notion of opaqueness is different for clients and servers.
For clients, they should be opaque. Nothing should be inferred from URI structure.
The server that minted the URI of course can look inside;
otherwise, it would need to maintain a (possibly infinite) lookup table.
And for the server, in the interest of sustainability and evolvability,
the design of the URI space benefits from being done properly.

> Tim Berners-Lee has noted that the query string portion of the URI is certainly not opaque and that furthermore, the path portion, separated by slashes, was no accident of design.

It's very important to give exact references here to avoid discussing these statements out of context.

> I also note that Leonard Richardson also make the case for non-opaque UR!s in his book RESTFul Web Services.

He makes the case for well-designed URIs;
not for clients looking into URIs (which is what non-opaqueness means).

Best,

Ruben

Kevin Swiber

unread,
Feb 17, 2016, 3:23:57 PM2/17/16
to api-...@googlegroups.com
I agree with much of what has already been said, but I'll add a couple of things.

The test I use to determine this answer is a judgement of whether or not the type of resource is independently significant from a semantic perspective.

If users and messages are an independently significant, each should probably have a top-level URL.  If the resources are only significant when coupled with a relationship to another resource, then consider modeling a filter on the primary resource.  Most filters are tucked to the right of the query string, but one could also opt for something like matrix parameters here.  I've actually used a SQL-like query language as a value of a query string parameter to handle cases of fine-grained filtering.

Note that it's also okay to have both a top-level resource and a filtered companion, but in this case, it's smart to think about how the models might differ when directly coupled with a relationship or when accessed independently.  Many times, I've found there is a difference.  When one gets to the position of opting for both, chances are the model complexity calls for it.

Good luck!


Cheers,

Kevin

On Tue, Feb 16, 2016 at 7:29 AM Jay C <join....@gmail.com> wrote:
What reasons are there to prefer pretty urls (e.g.) /users/1/messages vs query strings (e.g.) messages?users=1

I am working with someone who believes all resources should be at the 1st level and all other data is placed in the query string (aka no pretty urls).  He believes that pretty urls are harder to implement and provide no benefit.

--

Paul Mansour

unread,
Feb 17, 2016, 3:51:34 PM2/17/16
to API Craft
Hi Ruben,

Thanks for the response.

I think both Fielding and Richardson argue (or used to argue) for more than simply a well-designed URI space for the benefit of the developers, like well ordered code or good variable names. 

Fielding writes:

In fact, RESTful applications are, at all times,
encouraged to use human-meaningful, hierarchical identifiers in order
to maximize the serendipitous use of the information beyond what is
anticipated by the original application.

And in addition:

However, once that list is provided,
people can and do anticipate the names of other/future resources in
that name space, just as I would often directly type URIs into the
location bar rather than go through some poorly designed interactive
multi-page interface for stock charts.

That seems pretty clear to me.

As for Richardson, on page 85 of his book he writes:

If a client knows the structure of the service's URIs, it can create its own entry points into the service. This makes it easy for clients to use your service in ways you didn't think of.

Both of these writings are fairly old, so perhaps they have changed their thoughts in this?  

With respect to Bernes-Lee, he writes  about an "opacity axiom" of URIs, but then he says:

Query strings are clearly not opaque to the client. 

and that:

The URI Syntax, now famous through its HTTP form uses slashes to indicate a hierarchical structured name or address. Apart from that, the strings between the slashes are opaque. 

Both of these statements seem to me to weaken the idea of an opaqueness "axiom".  

Paul


Paul Mansour

unread,
Feb 17, 2016, 3:56:49 PM2/17/16
to API Craft

Both of these statements seem to me to weaken the idea of an opaqueness "axiom".  

Paul

I should note that Berners-Lee prefaces his notes on this topic with a warning that his use of the word "axiom" is not particularly rigorous.

Kijana Woodard

unread,
Feb 17, 2016, 4:26:01 PM2/17/16
to api-...@googlegroups.com
A bit further down the thread, Mr. Fielding responds:

> where the client can substitute into the $1 position to obtain a URI 
> and
> have some reasonable expectation that the server manages a
> corresponding resource.

Reasonable expectation? Hmmm. All links are wishful thinking.
Guessed links are just somewhat more wishful than others.

Humans navigating the web is a different matter since humans are more flexible to changes.
Given that "guessed links" are "more wishful", I think "opaqueness" is a fair starting point for a client consuming an API.

What's the other choice?

The client can, at some point, guess at other urls. If those "work", great. If they later stop working, the client should gracefully recover and discover the proper url from the server. 

Why not just discover them in the first place?




--

Chris Mullins

unread,
Feb 17, 2016, 7:30:08 PM2/17/16
to API Craft
You should optimize to make things easier for your API consumers. 

If that means clear URL's that are easy to type, easy to understand, and require little documentation you should bias in that direction. 

If that means you've got specific clients using a specific stack and they have a preference for query strings, you should bias in that direction. 

The amount of work for you - the API implementer - is irrelevant for a few reasons:
  1. Your customers just don't care how hard it was for you. Nor should they. 
  2. If you build the wrong thing, you won't have customers. 
  3. If you build the right thing, you might have customers. 
  4. You're doing this once. Ideally you'll have many customers so making less work for them is critical. 
For me, pretty URL's mean "Time to First Call" is greatly reduced and support is reduced. 

The less docs folks need to read, the more "obvious" your examples are, and the more they are immediately able to grok what's going on, the better. 

Cheers,
Chris

Darrel Miller

unread,
Feb 17, 2016, 7:48:34 PM2/17/16
to api-...@googlegroups.com

If the top priority is making things easier for API consumers then the best option is to provide URI templates embedded in responses.  That way an API consumer never has to ever think about what a URL looks like, not how to construct it.

 

Darrel

--

Filippos Vasilakis

unread,
Mar 2, 2016, 3:14:06 AM3/2/16
to API Craft
In my opinion and my experience, your friend is right, consider the following:

Let's say that you have a Video, Post, Group and Comment resources:

A video:
GET   /api/v1/videos/:video_id
A post:
GET   /api/v1/posts/:post_id
A group:
GET   /api/v1/groups/:group_id
A Comment:
GET   /api/v1/comments/:comment_id

Let's add comments to a video
GET   /api/v1/videos/:video_id/comments

Let's add comments to a post:
GET   /api/v1/post/:post_id/comments

Let's add comment to a.. comment! (of a video!)
GET   /api/v1/videos/:video_id/comments/:comment_id/comments

This doesn't look promising!

Let's ask for comments of a post that belongs to a group:
GET   /api/v1/videos/:group_id/posts/:post_id/comments

Let's ask for comments of a comment of a post that belongs to a group:
GET   /api/v1/videos/:group_id/posts/:post_id/comments/:comment_id/comments

You see where is going..... and this is only for 1 resource!! For 4 resources it's going to be hell!

Why not just:
GET   /api/v1/comments?video_id=1
GET   /api/v1/comments?post_id=1
GET   /api/v1/comments?video_id=1&comment_id=3
GET   /api/v1/comments?group_id=1&comment_id=3
GET   /api/v1/comments?group_id=1&post_id=3&comment_id=3
POST  /api/v1/comments //all comment association data are in the body of the POST request

Having only 1 endpoint for Comments resource is better because it's less complex for both the front-end and the backend. In the backend you will have to deal only with one part of code that handles this endpoint, and then have a ServiceObject or whatever that handles the query params and runs the correct sql/nosql queries (which you can unit test). Also, in the front-end dealing with query params is much easier as well. For instance, in Ember:
this.get('store').query('comments', {
  group_id: 1,
  post_id: 3,
  comment_id: 3
  sort: { property: 'published_at', order: 'desc }
});
This goes in sync with nested filters, like you want to filter all comments from group 3 but only those which post is private:
this.get('store').query('comments', {
  group_id: 1,
  post: { private: true},
  sort: { property: 'published_at', order: 'desc }
});

In general, I would say query params offer much more flexibility than endpoints.

Also, there is another issue with resource-based endponts: 
You can't request a resource for multiple parent resources. For instance, let's say that I want all comments of 2 videos/posts etc. That's impossible. Instead, you could do:
GET   /api/v1/comments?post_id[]=1&video_id[]=3
GET   /api/v1/comments?user_id[]=1&user_id[]=3

As I said, constructing params of a url in the client is much much easier than constructing the actual URL. After all, comments is what you want, that is, the resource is the same. Why not having a conistent url for that?

HOWEVER, if your resource representation changes substantially, then you should have a different endpoint. For instance, if the comments in your App have a specific format, but the comments of a video have a (not slightly) different format, then you should dedicate a different resource endpoint for the latter. Also, some resources MUST be nested. For instance followers (followers of what/whom?).
Reply all
Reply to author
Forward
0 new messages