aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md43
-rw-r--r--core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala13
-rw-r--r--tests/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala8
3 files changed, 60 insertions, 4 deletions
diff --git a/README.md b/README.md
index 28a6238..cfe8a85 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,49 @@ implicit val handler = HttpConnectionSttpHandler
Any request definition starts from `sttp`: the empty request. This can be further customised, each time yielding a new,
immutable request description (unless a mutable body is set on the request, such as a byte array).
+## URI interpolator
+
+Using the URI interpolator it's possible to conveniently create `java.net.URI` instances, which can then be used
+to specify request endpoints, for example:
+
+```scala
+import com.softwaremill.sttp._
+import java.net.URI
+
+val user = "Mary Smith"
+val filter = "programming languages"
+
+val endpoint: URI = uri"http://example.com/$user/skills?filter=$filter"
+```
+
+Any values embedded in the URI will be URL-encoded, taking into account the context (e.g., the whitespace in `user` will
+be %-encoded as `%20D`, while the whitespace in `filter` will be query-encoded as `+`).
+
+The possibilities of the interpolator don't end here. Other supported features:
+
+* parameters can have optional values: if the value of a parameter is `None`, it will be removed
+* maps, sequences of tuples and sequences of values can be embedded in the query part. They will be expanded into
+query parameters. Maps and sequences of tuples can also contain optional values, for which mappings will be removed
+if `None`.
+* optional values in the host part will be expanded to a subdomain if `Some`, removed if `None`
+* sequences in the host part will be expanded to a subdomain sequence
+
+A fully-featured example:
+
+```scala
+import com.softwaremill.sttp._
+val secure = true
+val scheme = if (secure) "https" else "http"
+val subdomains = List("sub1", "sub2")
+val vx = Some("y z")
+val params = Map("a" -> 1, "b" -> 2)
+val jumpTo = Some("section2")
+uri"$scheme://$subdomains.example.com?x=$vx&$params#$jumpTo"
+
+// generates:
+// https://sub1.sub2.example.com?x=y+z&a=1&b=2#section2
+```
+
## Request types
All requests have type `RequestTemplate[U]`, where `U[_]` specifies if the request method and URL are specified. There
diff --git a/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala b/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala
index 294d6ce..4bc2a0b 100644
--- a/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala
+++ b/core/src/main/scala/com/softwaremill/sttp/UriInterpolator.scala
@@ -163,19 +163,26 @@ object UriInterpolator {
override def parseE(e: Any): UriBuilder = e match {
case m: Map[_, _] =>
- val flattenedMap = m.flatMap {
+ val flattenedM = m.flatMap {
case (_, None) => None
case (k, Some(v)) => Some((k, v))
case (k, v) => Some((k, v))
}
- val newFragments = flattenedMap.map {
+ val newFragments = flattenedM.map {
case (k, v) =>
(Some(encode(k, query = true)), Some(encode(v, query = true)))
}
copy(fs = fs ++ newFragments)
case s: Seq[_] =>
- val newFragments = s.map {
+ val flattenedS = s.flatMap {
+ case (_, None) => None
+ case (k, Some(v)) => Some((k, v))
+ case None => None
+ case Some(k) => Some(k)
+ case x => Some(x)
+ }
+ val newFragments = flattenedS.map {
case (k, v) =>
(Some(encode(k, query = true)), Some(encode(v, query = true)))
case x => (Some(encode(x, query = true)), None)
diff --git a/tests/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala b/tests/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala
index d7719fd..df26f66 100644
--- a/tests/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala
+++ b/tests/src/test/scala/com/softwaremill/sttp/UriInterpolatorTests.scala
@@ -88,7 +88,13 @@ class UriInterpolatorTests extends FunSuite with Matchers {
(uri"http://example.com?x=y&${Map("a" -> None)}",
s"http://example.com?x=y"),
(uri"http://example.com?x=y&${Map("a" -> Some("b"))}",
- s"http://example.com?x=y&a=b")
+ s"http://example.com?x=y&a=b"),
+ (uri"http://example.com?x=y&${Seq("a" -> None)}",
+ s"http://example.com?x=y")
+ ),
+ "fragments" -> List(
+ (uri"http://example.com#$v1", s"http://example.com#$v1"),
+ (uri"http://example.com#$None", s"http://example.com")
),
"everything" -> List(
(uri"${"http"}://$v1.$v2.com/$v1/$v2?$v1=$v2&$v3=$v4#$v1",