Usage

Parsing

Parsing an URI Template at compile time can be achieved as follows:

import uritemplate4s._

val template = uritemplate"http://example.com/search{?q,lang}"

When an invalid template is supplied, the error will be shown at compile time.

scala> uritemplate"http://example.com/search{q"
       uritemplate"http://example.com/search{q"
       ^
On line 2: error: not a valid URI Template, Position 1:28, found ""

URI Templates are usually dynamically provided, and so will need to be parsed at runtime like so:

val rawTemplate = "http://example.com/search{?q,lang}"
// rawTemplate: String = http://example.com/search{?q,lang}

val parseResult = UriTemplate.parse(rawTemplate)
// parseResult: Either[uritemplate4s.ParseFailure,uritemplate4s.UriTemplate] = Right(ComponentsUriTemplate(List(LiteralComponent(Encoded(http://example.com/search)), Expression(Query,List(Varspec(q,EmptyModifier), Varspec(lang,EmptyModifier))))))

Because parsing a template can fail, the result is an Either of type Either[ParseFailure, UriTemplate].

When parsing fails the result is a Left containing the error with details of the cause.

UriTemplate.parse("http://example.com/search{q")
// res1: Either[uritemplate4s.ParseFailure,uritemplate4s.UriTemplate] = Left(uritemplate4s.ParseFailure: Position 1:28, found "")

To extract the parsed URI Template from the Either, pattern matching can be used:

val template: UriTemplate = UriTemplate.parse(rawTemplate) match {
  case Left(error) => throw error
  case Right(parsedTemplate) => parsedTemplate
}

Or more simply:

val template: UriTemplate = UriTemplate.parse(rawTemplate).toTry.get

Template Expansion

A template can be expanded by supplying tuples representing the name/value pairs to be used in expansion.

template.expand("q" -> "After the Quake", "lang" -> "en")
// res2: uritemplate4s.ExpandResult = Success(http://example.com/search?q=After%20the%20Quake&lang=en)

In the previous example it should be noted that the resultant URI is wrapped in a ExpandResult.Success. There are some possible soft failures which can occur during template expansion, meaning an expansion result could be either a ExpandResult.Success or a ExpandResult.PartialSuccess.

To extract the result from either case, the .value field can be used.

val uri = template.expand("q" -> "After the Quake", "lang" -> "en").value
// uri: String = http://example.com/search?q=After%20the%20Quake&lang=en

For examples and details of the features supported in URI Template expansion, refer to RFC 6570 Section 3 as well as the tests included in this project.

List Expansion

List expansion is supported as defined in RFC 6570 Level 4.

val listTemplate = UriTemplate.parse("/search{?list}").toTry.get
// listTemplate: uritemplate4s.UriTemplate = ComponentsUriTemplate(List(LiteralComponent(Encoded(/search)), Expression(Query,List(Varspec(list,EmptyModifier)))))

val seq = Seq("red", "green", "blue")
// seq: Seq[String] = List(red, green, blue)

listTemplate.expand("list" -> seq).value
// res3: String = /search?list=red,green,blue

List and Vectors are also supported.

listTemplate.expand("list" -> seq.toList).value
listTemplate.expand("list" -> seq.toVector).value

Associative Array Expansion

Associative array expansion is supported as defined in RFC 6570 Level 4.

val assocTemplate = UriTemplate.parse("/search{?address*}").toTry.get
// assocTemplate: uritemplate4s.UriTemplate = ComponentsUriTemplate(List(LiteralComponent(Encoded(/search)), Expression(Query,List(Varspec(address,Explode)))))

val addressMap = Map("city" -> "Manchester", "country" -> "England", "postcode" -> "M2 5DB")
// addressMap: scala.collection.immutable.Map[String,String] = Map(city -> Manchester, country -> England, postcode -> M2 5DB)

assocTemplate.expand("address" -> addressMap).value
// res6: String = /search?city=Manchester&country=England&postcode=M2%205DB