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

    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-uri-template</artifactId>
      <version>5.0.5</version>
    </dependency>

- Gradle (in your `build.gradle` file):

    compile 'io.vertx:vertx-uri-template:5.0.5'

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