Vert.x URI Template

An implementation of the URI Template RFC.

This implements the spec level 4.

Warning
This module has Tech Preview status, this means the API can change between versions.

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):

<dependency>
 <groupId>io.vertx</groupId>
 <artifactId>vertx-uri-template</artifactId>
 <version>4.3.0</version>
</dependency>
  • Gradle (in your build.gradle file):

compile io.vertx:vertx-uri-template:4.3.0

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.

Note
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.

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 #.

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-_.~