spring-projects / spring-hateoas

Spring HATEOAS - Library to support implementing representations for hyper-text driven REST web services.
https://spring.io/projects/spring-hateoas
Apache License 2.0
1.04k stars 477 forks source link

Allow URI Template with variable names starts with $ character #246

Closed fgilbert closed 4 years ago

fgilbert commented 10 years ago

Hi, I would like to create an URI template with a variable name starts with $ character. It doesn't work when I instanciate UriTemplate with a template string like this : http://localhost/foo/bar{?$filter} But it works with a base URI ( http://localhost/foo/bar) and template variable object, see unit tests.

This is due to the fact that the variable RegExp \{([\?\&#\/]?)([\w\,]+)\} used in the UriTemplate(String) constructor doesn't accept $ character. However, according to RFC 6570 - URI Template (http://tools.ietf.org/html/rfc6570), §2.2 Expressions :

The expression syntax specifically excludes use of the dollar ("$") and parentheses ["(" and ")"] characters so that they remain available for use outside the scope of this specification. For example, a macro language might use these characters to apply macro substitution to a string prior to that string being processed as a URI Template.

Unit Test KO with template String -> IllegalArgumentException :

Map<String, String> arguments = new HashMap<String, String>();
arguments.put("$filter", "aaa");
UriTemplate uriTemp1 = new UriTemplate("http://localhost/foo/bar{?$filter}");
Link selfLink = new Link(uriTemp1, Link.REL_SELF);
selfLink.expand(arguments);
Assert.assertEquals("http://localhost/foo/bar?$filter=aaa", selfLink.getHref());

Unit Test OK with TemplateVariable Object :

Map<String, String> arguments = new HashMap<String, String>();
arguments.put("$filter", "aaa");
TemplateVariable tempVarFilter = new TemplateVariable("$filter", TemplateVariable.VariableType.REQUEST_PARAM);
UriTemplate uriTemp1 = new UriTemplate("http://localhost/foo/bar", new TemplateVariables(tempVarFilter));
Link selfLink = new Link(uriTemp1, Link.REL_SELF);
selfLink = selfLink.expand(arguments);

try {
    Assert.assertEquals("http://localhost/foo/bar?$filter=aaa", URLDecoder.decode(selfLink.getHref(), "UTF-8"));
}
catch (UnsupportedEncodingException l_e) {
    Assert.fail();
}

Thanks

sfussenegger commented 8 years ago

The important part from the RFC is in section 2.3. Variables:

varname = varchar *( ["."] varchar ) varchar = ALPHA / DIGIT / "_" / pct-encoded

so variable names have to start with either a character, digit, underscore or any percent-encoded character (pct-encoded = "%" HEXDIG HEXDIG).

While percent-encoded characters would be your best option, the regex in UriTemplate doesn't support it right now: it's ([\w\,]+) (with \w being short for [a-zA-Z_0-9]). Thus, the implementation really is this at the moment:

varname = *( varchar ) varchar = ALPHA / DIGIT / "_"

sfussenegger commented 8 years ago

I've created #475 for better support of RFC compliant variable names

gregturn commented 4 years ago

Superceded by #475.