-
Notifications
You must be signed in to change notification settings - Fork 65
Route Creation
(See Rho Examples Project for the most up to date examples)
The RhoRoutes[F[_]]
is the primary method for creating routes. Route creation is performed in the constructor using combinators defined in the rho package object.
/// src_inlined SimplePath core/src/test/scala/ApiExamples.scala
new RhoRoutes[IO] {
GET / "hello" |>> { () => Ok("Hello, world!") }
}
/// end_src_inlined
The rho DSL defines helpers for creating path, query, and header rules which will match and/or extract data from the Request
. All of these rules can be stored and used in the creation of more complex routes:
/// src_inlined ReusePath core/src/test/scala/ApiExamples.scala
new RhoRoutes[IO] {
// A path can be built up in multiple steps and the parts reused
val pathPart1 = GET / "hello"
pathPart1 / "world" |>> { () => Ok("Hello, world!") }
pathPart1 / "you" |>> { () => Ok("Hello, you!") }
}
/// end_src_inlined
Path rules are concerned with defining the path portion of the route. Portions of the path can be matched or captured:
/// src_inlined PathCapture core/src/test/scala/ApiExamples.scala
new RhoRoutes[IO] {
// Use combinators to parse and capture path parameters
GET / "helloworldnumber" / pathVar[Int] / "foo" |>> { i: Int =>
Ok("Received $i")
}
// the symbol 'world just says 'capture a String' with variable name "world"
GET / "helloworldstring" / 'world / "foo" |>> { i: String =>
Ok("Received $i")
}
}
/// end_src_inlined
The entire rest of the path can be captured using the *
rule:
/// src_inlined CaptureTail core/src/test/scala/ApiExamples.scala
new RhoRoutes[IO] {
// You can capture the entire rest of the tail using *
GET / "hello" / * |>> { r: List[String] =>
Ok(s"Got the rest: ${r.mkString}")
}
}
/// end_src_inlined
Query rules are captured in essentially the same manner as path rules:
/// src_inlined QueryCapture core/src/test/scala/ApiExamples.scala
new RhoRoutes[IO] {
// Query parameters can be captured in a similar manner as path fragments
GET / "hello" +? param[Int]("fav") |>> { i: Int =>
Ok(s"Query 'fav' had Int value $i")
}
}
/// end_src_inlined
Of course you can use query capture rules with path capture rules:
/// src_inlined MultiCapture core/src/test/scala/ApiExamples.scala
new RhoRoutes[IO] {
// A Path can be made all at once
POST / pathVar[Int] +? param[Int]("fav") |>> { (i1: Int, i2: Int) =>
Ok(s"Sum of the number is ${i1 + i2}")
}
}
/// end_src_inlined
Headers work essentially the same as path and query rules:
/// src_inlined HeaderCapture core/src/test/scala/ApiExamples.scala
new RhoRoutes[IO] {
GET / "hello" >>> capture(ETag) |>> { tag: ETag =>
Ok(s"Thanks for the tag: $tag")
}
}
/// end_src_inlined
Status codes are not necessarily required: rho will accept anything with an EntityEncoder
:
/// src_inlined ResultTypes core/src/test/scala/ApiExamples.scala
new RhoRoutes[IO] {
private val counter = new AtomicInteger(0)
private def getCount(): String = counter.incrementAndGet().toString
// Don't want status codes? Anything with an `EntityEncoder` will work.
GET / "nostatus" |>> { () => "No status!" }
GET / "taskNoStatus" |>> { () => Task(getCount())
}
/* Results need not be functions: they can be anything that has
an `EntityEncoder` instance in scope */
GET / "nostatus2" |>> "This is a constant result!"
GET / "taskNoStatus2" |>> Task(getCount())
/* We can use a standard http4s.Response, but we don't get any metadata
with it. Useful for things like Websocket support. */
GET / "websockets" |>> { () =>
val exchange: stream.Exchange[WebSocketFrame,WebSocketFrame] = ???
WS(exchange)
}
}
/// end_src_inlined
Rho stores as much metadata as it can, including status codes and the response types that accompany them which is very useful for middleware that can take advantage of that information (such as Swagger generation). In order to capture that data use the status code helpers:
/// src_inlined StatusCodes core/src/test/scala/ApiExamples.scala
new RhoRoutes[IO] {
GET / "twoResults" |>> { () =>
if (true) Ok("bytes result".getBytes())
else NotFound("Boo... Not found...")
}
}
/// end_src_inlined
For requests that contain a body rho can extract and decode it using the ^
operator with http4s EntityDecoder[A]
's:
/// src_inlined Decoders core/src/test/scala/ApiExamples.scala
new RhoRoutes[IO] {
// Using decoders you can parse the body as well
POST / "postSomething" ^ UrlForm.entityDecoder |>> { m: UrlForm =>
Ok(s"You posted these things: $m")
}
}
/// end_src_inlined