W3C home > Mailing lists > Public > uri@w3.org > October 2007

Re: URI Templates - optional variables?

From: Roy T. Fielding <fielding@gbiv.com>
Date: Mon, 15 Oct 2007 17:11:12 -0700
Message-Id: <797F3923-4585-4746-991A-679A5ED63F7A@gbiv.com>
Cc: Joe Gregorio <joe@bitworking.org>, Stefan Eissing <stefan.eissing@greenbytes.de>, Mark Nottingham <mnot@mnot.net>
To: URI <uri@w3.org>

I think it is critical to limit the potential operations to
typical string operations, both for simplicity of implementation
and also for our capacity to understand the template without
needing to refer to external rules or processing.  There is no
reason to have URI templates if we don't limit them to a
declarative syntax

In particular, anything turing complete would be way out of
bounds because that would cross from an in-band description
language to an out of band processing language.  URI templates
lose their value as a declarative syntax if they try to do what
javascript already does well enough.  Even regex would be far
more complex than any of the use cases require.  And I don't
want to see URI templates on the side of a bus -- that would
reintroduce long-term client/server coupling.

The characters I chose for delimiters are not important.  If we
want to avoid URI characters, then Joe's variation is good,
though it will make life slightly harder on XML config authors.
I think the set below is very easy to read, keeping in mind
that human language is not universal.

To tie this back to my earlier messages on Aug 1, substituting
pipe ("|") for ":", "<" for "?", adding ">" for suffix, and
"+" for simple joins:

    {variable}                                   (substitute)
       Substitute the value of variable.

    {=default|variable}                          (sub w/default)
       If variable is defined and non-empty, then substitute the
       value of variable.  Otherwise, substitute with the default
       value defined by the string of non-pipe characters between
       the '=' and '|', if any.
           E.g.,  {=red|favoritecolor}  = "value" or "red"

    {<prefix|variable}                           (prefixed sub)
       If variable is defined and non-empty, then substitute the
       string of non-pipe characters between the '<' and '|', if
       any, followed by the value of variable.  Otherwise,
       substitute with the empty string.
          E.g.,   {</|variable}       = "/value"      or ""
                  {<;name=|variable}  = ";name=value" or ""
                  {<#|variable}       = "#value"      or ""

    {>suffix|variable}                           (suffixed sub)
       If variable is defined and non-empty, then substitute the
       value of variable followed by the suffix string of non-pipe
       characters between the '>' and '|', if any.  Otherwise,
       substitute with the empty string.
          E.g.,   {>/|variable}       = "value/"      or ""
                  {>.html|variable}   = "value.html"  or ""

    {+separator|var1,var2,var3,...}              (join)
       For each variable named in the comma-separated list,
       if the named variable is defined and non-empty, then
       substitute the concatenation of variable values separated,
       if more than one substitution is made, with the string of
       non-pipe separator characters between the '+' and '|'.
          E.g., name     = "Fred"
                age      = "41"
                zip      = ""
                location = "USA"
         {+,|name,age,zip,location}    = "Fred,41,USA"
         {+ish;|name,age,zip,location} = "Fredish;41ish;USA"
         {+/|location,age}             = "USA/41"

    {,separator|var1,var2,var3,...}              (param=value sub)
       For each variable named in the comma-separated list,
       if the named variable is defined and non-empty, then
       substitute the concatenation of variable name, "=",
       variable value.  If more than one substitution is made,
       separate each substitution with the string of non-pipe
       separator characters between the ',' and '|'.
          E.g., name     = "Fred"
                age      = "41"
                zip      = ""
                location = "USA"
         {,&|name,age,zip,location} = "name=Fred&age=41&location=USA"
         {,;|name,age,zip,location} = "name=Fred;age=41;location=USA"

    {-offset|variable}
    {-offset-length|variable}                    (substring sub)
       Substitute a substring of the value of variable, as delimited
       by the non-negative integer offset from the beginning of the
       value string (0 = start of string) and including the remaining
       characters (if any) up to the maximum given by the positive
       integer length.  offset must be in the range [0-255].  length
       must be in the range [1-256].
           E.g.,  {-0-3|variable}   = "val"   or ""
                  {-3-2|variable}   = "ue"    or ""
                  {-3-8|variable}   = "ue"    or ""
                  {-2|variable}     = "lues"  or ""

The main use case for substring substitution is to describe
automated resource hierarchies that aren't flat, such as lists of
users within a large intranet that are tree-balanced by splitting
into sub-collections by the first character of the last name (this
is a very common case at my work where thousands of users are often
stored within a tree of JCR-based content).  Caches frequently do
the same type of content balancing by splitting stored messages by
the first few characters in a hash of the URI.  As Mark said, this
could be accomplished by external processing of the original
variable value, thereby defining a new variable to be used in the
template, but then how do we describe such processing to readers
of the URI template?  IMO, mapping values to identifier string is
the whole point of this exercise, so any case that we don't handle
within the declarative syntax is the same as punting to javascript.

One variation that might be worth considering:  If all of the map
operators are delimited on both sides by a pipe character, as in

     {variable}                  = "value"        or "red"
     {|=red|favoritecolor}       = "value"        or "red"
     {|<;name=|variable}         = ";name=value"  or ""
     {|>.html|variable}          = "value.html"   or ""
     {|+,|name,age,zip,location} = "Fred,41,USA"
     {|,&|name,age,zip,location} = "name=Fred&age=41&location=USA"
     {|-0-3|variable}            = "val"          or ""

then the template processor need only special-case the pipe "|"
and some people may find that easier to read.  *shrug*

....Roy
Received on Tuesday, 16 October 2007 00:11:27 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Thursday, 13 January 2011 12:15:37 GMT