[PSR-13] URI templates and URI objects

282 views
Skip to first unread message

Larry Garfield

unread,
Jun 2, 2016, 8:35:01 PM6/2/16
to php...@googlegroups.com, b...@nocarrier.co.uk
The last remaining items on PSR-13 are closely related, so they make sense to me to handle together.  The todo items are:

* Should Href be a string, or can/should we use PSR-7 URI objects? I'm very very tempted to go with the latter.
* Currently, technically, URL templates would be disallowed. That's a problem for, say, HAL. How do we want to square
  that, especially if Href becomes an object?
URI templates (see RFC 6570[1]) are a little weird.  They're not a "real" relationship.  Rather, they're a template for a relationship.  Formats like HAL make extensive use of them.  Others, like HTML, basically never use them and they're probably not legal.  (I've not checked, though.)  That makes supporting them problematic, as then they're valid only in some serializations and not others.  Additionally, the full RFC syntax is quite involved.  I've yet to see a PHP implementation that is complete.  (Symfony, for instance, uses an abridged version of the syntax for placeholders but not for URI arguments.) At the same time, we could consider using a URI object rather than a string.  That offers the advantage of being more formal and structured, and there's likely more tooling built up around that.  As a string, it can be in any of the zillion legal formats for URIs.  The URI object from PSR-7, by design, abstracts all of that messiness away.  However, I don't know how that would handle a templated URI.  Would that break PSR-7? I see a few options, none of which I particularly like: 1) Disallow templated URLs, and use a string URL.  This keeps the spec nice and simple, but basically precludes HAL from using it.  That seems a non-starter. 2) Disallow templated URLs, and use a URI object.  Same points as option 1, but more formal. 3) Disallow templated URLs, use a string URL, but specifically restrict it to only a few types of URL.  Specifically, either a fully qualified URL or a relative path fragment.  We can lock down all of the various fiddly bits and be "conservative in what you send".  Remember that we're talking only about the getter, no setter, so we have the flexibility to make the spec not flexible if it helps. :-)  (That said, there's a lot of forms that could be valid, legal, and useful.) 4) Allow templated URLs, using a string.  Lock it down a la option 3.  Specify that a Serializer for a context where templated URLs don't make sense MUST ignore those links.  I am unsure if that is safe to do. 5) Allow templated URLs, but only a subset of the spec (to make it actually possible to implement), for some definition of subset.  Specify that a Serializer must ignore templated URLs when they don't make sense. 6) Use a URI object, and coax it to somehow make templated URLs legal.  I am wary of whether this is even possible.  We then still have to deal with the Serializer context question. And probably other combinations of the options listed above. Thoughts?  Comments? Suggestions? [1] https://tools.ietf.org/html/rfc6570 --Larry Garfield

Larry Garfield

unread,
Jun 2, 2016, 8:36:50 PM6/2/16
to php...@googlegroups.com, b...@nocarrier.co.uk
Well, my mail client screwed that up, didn't it... Trying again...

Matthew Weier O'Phinney

unread,
Jun 8, 2016, 6:07:39 PM6/8/16
to php...@googlegroups.com
On Thu, Jun 2, 2016 at 7:36 PM, Larry Garfield <la...@garfieldtech.com> wrote:
<snip>
Larry and I just had a discussion on this over IRC. The main reason
URI templates come up is because the HAL specification
(https://tools.ietf.org/html/draft-kelly-json-hal-08#section-5)
defines links such that they may either follow RFC 3986 (URIs) **OR**
RFC 6570 (URI Templates). HAL is not the only one using RFC 6570, but
*is* one of the more widely adopted formats for REST APIs when using
JSON. I've seen a number of other libraries use them as well, making
it a compelling target.

What this means is:

- The URI could be fully qualified (per RFC 3986)
- Or it could be a URI template, which is often not valid per RFC 3986
(due to some of the expressions used)

Unfortunately, URI Templates are not universally useful; HTML, for
instance, would not be able to use them for <a> links.

As such, the only way we can determine to allow URI templates is:

- Have getHref() return a string
- Introduce a new isTemplated() method, to test whether the href
should be considered a URI Template.

Does anybody object to this?

--
Matthew Weier O'Phinney
mweiero...@gmail.com
https://mwop.net/

Tobion

unread,
Jun 8, 2016, 6:49:49 PM6/8/16
to PHP Framework Interoperability Group
Why not let getHref return UriIntface|UriTemplateInterface ?
UriTemplateInterface needs to be defined then. Maybe UriTemplateInterface  only needs to require a __toString.
Then the IsTemplate method is not needed and is can also not return wrong info.

Larry Garfield

unread,
Jun 9, 2016, 11:45:41 AM6/9/16
to php...@googlegroups.com
On 06/08/2016 05:49 PM, Tobion wrote:
> Why not let getHref return UriIntface|UriTemplateInterface ?
> UriTemplateInterface needs to be defined then.
> Maybe UriTemplateInterface only needs to require a __toString.
> Then the IsTemplate method is not needed and is can also not return
> wrong info.

Because inconsistent returns are ugly and error prone. It means anyone
calling the method MUST wrap the result in an if statement or risk a
fatal error. Their valid use cases are very narrow.

Also, that means defining UriTemplateInterface, which would be a
considerable extra challenge for this PSR.

Also, this is a bottom-posting thread. Please don't top post.

--Larry Garfield

Larry Garfield

unread,
Jun 15, 2016, 4:31:34 PM6/15/16
to php...@googlegroups.com
A corresponding PR has been filed here:

https://github.com/php-fig/fig-standards/pull/775

Including the following open question: Should we add utility methods
to LinkCollectionInterface to get just templated or untemplated values?
Or does that result in too much complexity alongside getLinksByRel()? Or
should that and getLinks() get a parameter to filter by templated or not?

--Larry Garfield

Matthew Weier O'Phinney

unread,
Jun 16, 2016, 4:38:39 PM6/16/16
to php...@googlegroups.com
On Wed, Jun 15, 2016 at 3:31 PM, Larry Garfield <la...@garfieldtech.com> wrote:
> A corresponding PR has been filed here:
>
> https://github.com/php-fig/fig-standards/pull/775
>
> Including the following open question: Should we add utility methods to
> LinkCollectionInterface to get just templated or untemplated values? Or does
> that result in too much complexity alongside getLinksByRel()? Or should that
> and getLinks() get a parameter to filter by templated or not?

I'd argue that we leave filtering to the consumer. This can be done when
iterating the collection, or could be delegated to a first-class collection:

$nonTemplatedLinks = new Collection($linkCollection->getLinks())
->reject(LinkInterface $link) {
return $link->isTemplated();
});

We did similarly with PSR-7, disallowing things like `withoutHeaders()` (note
the plural) and `clearHeaders()` in favor of a single `withoutHeader()`
(singular) method, among others. The rationale is:

- One method versus many (keeps interface focused, and eliminates TMTOWTDI
problems)
- Boolean flags as arguments are difficult to understand at invocation:
`$links->getLinksByRel('foo', true)` (what does `true` imply here?)

Since the methods in `LinkCollection` are already returning arrays (or iterable
objects), we'd either need to add more methods, or add flags, which leaves me
inclined to leave filtering up to the consumer.

Larry Garfield

unread,
Jun 20, 2016, 4:28:13 PM6/20/16
to php...@googlegroups.com
Makes sense. Care to merge that PR then? :-)

--Larry Garfield

Larry Garfield

unread,
Jul 7, 2016, 8:05:27 PM7/7/16
to php...@googlegroups.com
Since there was no pushback for over 20 days, I went ahead and merged it
myself.

--Larry Garfield
Reply all
Reply to author
Forward
0 new messages