Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding the UriTemplate class to implement RFC6570 #153

Merged
merged 29 commits into from
Jan 28, 2020

Conversation

nyamsprod
Copy link
Member

@nyamsprod nyamsprod commented Jan 21, 2020

Enhancement

Following the fact that Guzzle 7.0 will drop its UriTemplate implementation see #2240. I'm adding one to the URI package based on the UriTemplate class found in Guzzle 6.5 but with 2 main differences:

  • nested array support is removed (ie array like the one used by http_build_query
  • the UriTemplate constructor takes a template and a set of default variables which are merge to the set of variables added with the UriTemplate::expand method. As such the latter method does not have a $template argument.

Here's the public API methods apart from the getter and wither.

<?php

use League/Uri/UriTemplate;

$template = 'http://example.com/{foo}/{bar}';
$uriTemplate = new UriTemplate($template, ['foo' => 'foo']);
$uriTemplate->getVariableNames(); //returns ['foo', 'bar']
$uri = $uriTemplate->expand(['bar' => 'baz']); //$uri is an instance of League/Uri/Uri
echo $uri, PHP_EOL; // displays http://example.com/foo/baz

The class and its API are based on:

@nyamsprod nyamsprod force-pushed the feature/implement-uri-template branch from d59ac9b to c7fa727 Compare January 21, 2020 22:12
@nyamsprod
Copy link
Member Author

the test should be adapted to use https://github.com/uri-templates/uritemplate-test

@nyamsprod nyamsprod force-pushed the feature/implement-uri-template branch from dd17e57 to d8a1a13 Compare January 23, 2020 17:05
@nyamsprod
Copy link
Member Author

@kelunik would you mind reviewing this PR which adds UriTemplate specification to the URI package.

Of note:

  • the class is based on Guzzle implementation which will be removed from the Guzzle package in version 7.
  • the interfaces will be moved to the uri-interfaces package once the review is deemed OK
  • while the code is based on the Guzzle implementation I've added more validation and hopefully made the code faster and changed the public API by making the class immutable.

the remaining issue before merging is how the following templates should be handle

  • http://example}toto and
  • http://example{toto

Currently they will throw because of the presence of a { and of a } but I can understand the argument of them not throwing because the expression is not present at all and they should just be ignore.

When regarding other implementations, the second example always throws but not the first one does not 🤷‍♂ IMHO they should either both throw or they should not.

thanks in advance of the remarks and suggestions 😉.

@kelunik
Copy link
Contributor

kelunik commented Jan 25, 2020

I haven't read the RFC nor used URI templates, yet, but I always wanted to do that. I guess you're mainly looking for an API review, as the correctness is pretty much covered by existing test suites?

Regarding your open question, I guess they should both throw, because it's likely a mistake. Isn't { and } anyway disallowed in URIs?

@nyamsprod
Copy link
Member Author

nyamsprod commented Jan 25, 2020

Indeed it' mainly a API review... for the {} they have special meaning in URITemplate RFC and they usage is well covered. Also the template is not a real URI it is a template so it should not obey URI rules before being expanded
My public API is mostly influence by the design of the Java, the Node and Python main implementations by the way.

@kelunik
Copy link
Contributor

kelunik commented Jan 25, 2020

If it's not a valid placeholder and thus not replaced, it'll end up in the expanded URI, no?

@nyamsprod
Copy link
Member Author

nyamsprod commented Jan 25, 2020

Currently with my implementation

<?php

$template = 'http://example.com/{foo';
$uriTemplate = new UriTemplate($template);
$uriTemplate->getVariableNames(); //returns []
echo $uriTemplate->expand(['foo' => 'bar']), PHP_EOL;
//this passes and produces http://example.com/{foo

$template = 'http://example.com/}foo/{foo}';
$uriTemplate = new UriTemplate($template);
$uriTemplate->getVariableNames(); //returns ['foo']
echo $uriTemplate->expand(['foo' => 'bar']), PHP_EOL;
//this passes and produces http://example.com/}foo/bar

but

<?php

$template = 'http://example.com/{foo/{foo}';
new UriTemplate($template);
//throws on instantiation

@nyamsprod
Copy link
Member Author

@kelunik after a good night sleep and reviewing other implementations again, I've decided to go the route of being more strict (ie ... all the examples I gave you above are now ALL throwing exception).

The reason being that:

  • if you missed one brace it probably is a typo that needs to be catch.
  • And if you really need one brace then the best way to escape it is to URL encode it.

This should resolve my last issue IMHO

@nyamsprod nyamsprod merged commit cd8e305 into master Jan 28, 2020
@nyamsprod nyamsprod deleted the feature/implement-uri-template branch January 28, 2020 18:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants