<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-uri-template</artifactId>
<version>5.0.0.CR2</version>
</dependency>
Vert.x URI Template
An implementation of the URI Template RFC.
This implements the spec level 4.
Using the URI Template
To use this component, add the following dependency to the dependencies section of your build descriptor:
-
Maven (in your
pom.xml
):
-
Gradle (in your
build.gradle
file):
compile 'io.vertx:vertx-uri-template:5.0.0.CR2'
Templates
You can create a template very easily
UriTemplate template = UriTemplate.of("http://{host}/product/{id}{?sort}");
Only a valid template can be created, any invalid template is rejected with an exception at creation time:
UriTemplate template = UriTemplate.of("{!invalid}}"); // Will throw an exception
Template expansion
You can call expandToString
with a list of variables to produce a valid URI string
UriTemplate template = UriTemplate.of("http://{host}/product/{id}{?sort}");
String uri = template.expandToString(Variables
.variables()
.set("host", "localhost")
.set("id", "12345")
.set("sort", "price")
);
Variables
holds the variables used by template expansion
-
you can set a single valued variable
variables.set("server", "localhost");
variables.set("port", "8080");
-
you can set a list valued variable
variables.set("ids", Arrays.asList("123", "456"));
-
you can set a map valued variable
Map<String, String> query = new HashMap<>();
query.put("firstName", "Dale");
query.put("lastName", "Cooper");
variables.set("query", query);
As seen earlier, variables are referenced within a template by their name surrounded with curly braces, e.g {host}
references the host
variable, this expansion is known as simple string expansion.
There are other expansion styles, they differ from simple string expansion by their formatting and encoding. |
Lists are expanded to a comma separated value
UriTemplate template = UriTemplate.of("http://server.com/products?sort={sort}");
Variables variables = Variables.variables().set("sort", Arrays.asList("price", "name"))
assertEquals("http://server.com/products?sort=price,name", template.expandToString(variables));
Likewise, map values are expanded to comma separated values, e.g { "firstName": "Dale", "lastName": "Cooper" }
expands to "firstName,Dale,lastName,Cooper"
, unless they are exploded with an asterisk modifier
UriTemplate template = UriTemplate.of("http://server.com/?details={details*}");
Map<String, String> details = new HashMap<>();
details.put("firstName", "Dale");
details.put("lastName", "Cooper");
Variables variables = Variables.variables().set("details", details)
assertEquals("http://server.com/?firstName=Dale,lastName=Cooper", template.expandToString(variables));
Template encoding
Literal characters outside the reserved set and unreserved set are percent-encoded:
assertEquals("http://server.com/currency/%E2%82%AC", UriTemplate.of("http://server.com/currency/€").expandToString(variables));
Simple string expansion encodes any character outside the unreserved set to its percent-encoded equivalent:
Variables variables = Variables.variables();
variables.set("currency", "€")
assertEquals("http://server.com/currency/%E2%82%AC", UriTemplate.of("http://server.com/currency/{currency}").expandToString(variables));
Expansion styles
Beyond simple string expansion, you can use other expansion styles, expansion follows the syntax '{' operator? varname '}'
.
Simple string expansion
The default expansion style when no operator is given.
-
Syntax:
{varname}
-
Allowed characters: unreserved set
Vars | Template | URI |
---|---|---|
{ "who": "fred" } | {who} | fred |
{ "unreserved": "_" } | {unreserved} | _ |
{ "reserved": "/" } | {reserved} | %2F |
{ "pct_encoded": "%2F" } | {pct_encoded} | %252F |
{ "x": "1024", "y" : "768" } | {x,y} | 1024/y768 |
{ "list": [ "red", "green", "blue" ] } | {list} | red,green,blue |
{ "list": [ "red", "green", "blue" ] } | {list*} | red,green,blue |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {map} | firstName,Dale,lastName,Cooper |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {map*} | firstName=Dale,lastName=Cooper |
Path segment expansion
Path segment expansion is useful for creating hierarchical URI path.
-
Syntax:
{/varname}
-
Allowed characters: unreserved set
Vars | Template | URI |
---|---|---|
{ "who": "fred" } | {/who} | /fred |
{ "unreserved": "_" } | {/unreserved} | /_ |
{ "reserved": "/" } | {/reserved} | /%2F |
{ "pct_encoded": "%2F" } | {/pct_encoded} | /%252F |
{ "x": "1024", "y" : "768" } | {/x,y} | /1024/y768 |
{ "list": [ "red", "green", "blue" ] } | {/list} | /red,green,blue |
{ "list": [ "red", "green", "blue" ] } | {/list*} | /red/green/blue |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {/map} | /firstName,Dale,lastName,Cooper |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {/map*} | /firstName=Dale/lastName=Cooper |
Form-style query expansion
Form-style query expansion is useful for creating query strings.
-
Syntax:
{?varname}
-
Allowed characters: unreserved set
Vars | Template | URI |
---|---|---|
{ "who": "fred" } | {?who} | ?who=fred |
{ "unreserved": "_" } | {?unreserved} | ?unreserved=_ |
{ "reserved": "/" } | {?reserved} | ?reserved=%2F |
{ "pct_encoded": "%2F" } | {?pct_encoded} | ?pct_encoded=%252F |
{ "x": "1024", "y" : "768" } | {?x,y} | ?x=1024&y768 |
{ "list": [ "red", "green", "blue" ] } | {?list} | ?list=red,green,blue |
{ "list": [ "red", "green", "blue" ] } | {?list*} | ?list=red&list=green&list=blue |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {?map} | ?map=firstName,Dale,lastName,Cooper |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {?map*} | ?firstName=Dale&lastName=Cooper |
Form-style query continuation
Form-style query continuation is useful for appending to query strings.
-
Syntax:
{&varname}
-
Allowed characters: unreserved set
Vars | Template | URI |
---|---|---|
{ "who": "fred" } | {&who} | &who=fred |
{ "unreserved": "_" } | {&unreserved} | &unreserved=_ |
{ "reserved": "/" } | {&reserved} | &reserved=%2F |
{ "pct_encoded": "%2F" } | {&pct_encoded} | &pct_encoded=%252F |
{ "x": "1024", "y" : "768" } | {&x,y} | &x=1024&y768 |
{ "list": [ "red", "green", "blue" ] } | {&list} | &list=red,green,blue |
{ "list": [ "red", "green", "blue" ] } | {&list*} | &list=red&list=green&list=blue |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {&map} | &map=firstName,Dale,lastName,Cooper |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {&map*} | &firstName=Dale&lastName=Cooper |
Reserved expansion
Extends the allowed character set of the simple string expansion to the reserved set and pct-encoded sequences.
-
Syntax:
{+varname}
-
Allowed characters: unreserved set, unreserved set and pct-encoded sequence.
Vars | Template | URI |
---|---|---|
{ "who": "fred" } | {+who} | fred |
{ "unreserved": "_" } | {+unreserved} | _ |
{ "reserved": "/" } | {+reserved} | / |
{ "pct_encoded": "%2F" } | {+pct_encoded} | %2F |
{ "x": "1024", "y" : "768" } | {+x,y} | 1024,y768 |
{ "list": [ "red", "green", "blue" ] } | {+list} | red,green,blue |
{ "list": [ "red", "green", "blue" ] } | {+list*} | red,green,blue |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {+map} | firstName,Dale,lastName,Cooper |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {+map*} | firstName=Dale,lastName=Cooper |
Fragment expansion
Like the reserved expansion prefixed by #
.
-
Syntax:
{#varname}
-
Allowed characters: unreserved set, unreserved set and pct-encoded
Vars | Template | URI |
---|---|---|
{ "who": "fred" } | {#who} | #fred |
{ "unreserved": "_" } | {#unreserved} | #_ |
{ "reserved": "/" } | {#reserved} | #/ |
{ "pct_encoded": "%2F" } | {#pct_encoded} | #%2F |
{ "x": "1024", "y" : "768" } | {#x,y} | #1024,y768 |
{ "list": [ "red", "green", "blue" ] } | {#list} | #red,green,blue |
{ "list": [ "red", "green", "blue" ] } | {#list*} | #red,green,blue |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {#map} | #firstName,Dale,lastName,Cooper |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {#map*} | #firstName=Dale,lastName=Cooper |
Label expansion with Dot-Prefix
-
Syntax:
{.varname}
-
Allowed characters: unreserved set
Vars | Template | URI |
---|---|---|
{ "who": "fred" } | {.who} | .fred |
{ "unreserved": "_" } | {.unreserved} | ._ |
{ "reserved": "/" } | {.reserved} | .%2F |
{ "pct_encoded": "%2F" } | {.pct_encoded} | .%252F |
{ "x": "1024", "y" : "768" } | {.x,y} | .1024.y768 |
{ "list": [ "red", "green", "blue" ] } | {.list} | .red,green,blue |
{ "list": [ "red", "green", "blue" ] } | {.list*} | .red.green.blue |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {.map} | .firstName,Dale,lastName,Cooper |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {.map*} | .firstName=Dale.lastName=Cooper |
Path-Style Parameter Expansion
-
Syntax:
{.varname}
-
Allowed characters: unreserved set
Vars | Template | URI |
---|---|---|
{ "who": "fred" } | {;who} | ;who=fred |
{ "unreserved": "_" } | {;unreserved} | ;unreserved=_ |
{ "reserved": "/" } | {;reserved} | ;reserved=%2F |
{ "pct_encoded": "%2F" } | {;pct_encoded} | ;pct_encoded=%252F |
{ "x": "1024", "y" : "768" } | {;x,y} | ;x=1024;y=y768 |
{ "list": [ "red", "green", "blue" ] } | {;list} | ;list=red,green,blue |
{ "list": [ "red", "green", "blue" ] } | {;list*} | ;list=red;list=green;list=blue |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {;map} | ;map=firstName,Dale,lastName,Cooper |
{ "map": { "firstName": "Dale", "lastName": "Cooper" } } | {;map*} | ;firstName=Dale;lastName=Cooper |
Characters set cheatsheet
Reserved set
!*'();:@&=+$,/?#[]
Unreserved set
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~