Skip to content

Commit

Permalink
Rename foldService to foldRoutes and others
Browse files Browse the repository at this point in the history
  • Loading branch information
chuwy committed Oct 7, 2018
1 parent b2a16ca commit acc4db3
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 34 deletions.
10 changes: 4 additions & 6 deletions core/src/main/scala/org/http4s/rho/CompileRoutes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,13 @@ object CompileRoutes {
implicit def compiler[F[_]]: CompileRoutes[F, RhoRoute.Tpe[F]] = identityCompiler[F]
}


/** Convert the `Seq` of [[RhoRoute]]'s into a `HttpService`
/** Convert the `Seq` of [[RhoRoute]]'s into a `HttpRoutes`
*
* @param routes `Seq` of routes to bundle into a service.
* @param filter [[RhoMiddleware]] to apply to the routes.
* @return An `HttpService`
* @return An `HttpRoutes`
*/
def foldRoutes[F[_]: Monad](routes: Seq[RhoRoute.Tpe[F]], filter: RhoMiddleware[F]): HttpRoutes[F] = {
val tree = filter(routes).foldLeft(PathTree[F]()){ (t, r) => t.appendRoute(r) }
def foldRoutes[F[_]: Monad](routes: Seq[RhoRoute.Tpe[F]]): HttpRoutes[F] = {
val tree = routes.foldLeft(PathTree[F]()){ (t, r) => t.appendRoute(r) }
Kleisli((req: Request[F]) => tree.getResult(req).toResponse)
}
}
8 changes: 4 additions & 4 deletions core/src/main/scala/org/http4s/rho/RhoService.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ import shapeless.{HList, HNil}
* [[CompileRoutes]] inside the constructor.
*
* {{{
* val srvc = new RhoService {
* val srvc = new RhoService[IO] {
* POST / "foo" / pathVar[Int] +? param[String]("param") |>> { (p1: Int, param: String) =>
* Ok("success")
* }
* }
*
* }}}
*
* @param routes Routes to prepend before elements in the constructor.
Expand Down Expand Up @@ -47,8 +46,9 @@ class RhoService[F[_]: Monad](routes: Seq[RhoRoute[F, _ <: HList]] = Vector.empt
/** Get a snapshot of the collection of [[RhoRoute]]'s accumulated so far */
final def getRoutes: Seq[RhoRoute[F, _ <: HList]] = serviceBuilder.routes()

/** Convert the [[RhoRoute]]'s accumulated into a `HttpService` */
final def toRoutes(filter: RhoMiddleware[F] = identity): HttpRoutes[F] = serviceBuilder.toService(filter)
/** Convert the [[RhoRoute]]'s accumulated into a `HttpRoutes` */
final def toRoutes(middleware: RhoMiddleware[F] = identity): HttpRoutes[F] =
serviceBuilder.toRoutes(middleware)

final override def toString: String = s"RhoService(${serviceBuilder.routes().toString()})"

Expand Down
17 changes: 8 additions & 9 deletions core/src/main/scala/org/http4s/rho/ServiceBuilder.scala
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
package org.http4s.rho

import scala.collection.immutable.VectorBuilder
import cats.Monad
import org.http4s._
import shapeless.HList
import org.http4s._

import scala.collection.immutable.VectorBuilder

/** CompileService which accumulates routes and can build a `HttpService` */
/** CompileService which accumulates routes and can build a `HttpRoutes` */
final class ServiceBuilder[F[_]: Monad] private(internalRoutes: VectorBuilder[RhoRoute.Tpe[F]]) extends CompileRoutes[F, RhoRoute.Tpe[F]] {

/** Turn the accumulated routes into an `HttpService`
/** Turn the accumulated routes into an `HttpRoutes`
*
* @param filter [[RhoMiddleware]] to apply to the collection of routes.
* @return An `HttpService` which can be mounted by http4s servers.
* @param middleware [[RhoMiddleware]] to apply to the collection of routes.
* @return An `HttpRoutes` which can be mounted by http4s servers.
*/
def toService(filter: RhoMiddleware[F] = identity): HttpRoutes[F] =
CompileRoutes.foldRoutes(internalRoutes.result(), filter)
def toRoutes(middleware: RhoMiddleware[F] = identity): HttpRoutes[F] =
CompileRoutes.foldRoutes(middleware.apply(internalRoutes.result()))

/** Get a snapshot of the currently acquired routes */
def routes(): Seq[RhoRoute.Tpe[F]] = internalRoutes.result()
Expand Down
10 changes: 5 additions & 5 deletions core/src/test/scala/org/http4s/rho/CompileRoutesSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ class CompileRoutesSpec extends Specification {
val c = ServiceBuilder[IO]()
getFoo(c)

"GetFoo" === RRunner(c.toService()).checkOk(Request(uri=Uri(path="/hello")))
"GetFoo" === RRunner(c.toRoutes()).checkOk(Request(uri=Uri(path="/hello")))
}

"Build multiple routes" in {
val c = ServiceBuilder[IO]()
getFoo(c)
putFoo(c)

"GetFoo" === RRunner(c.toService()).checkOk(Request(uri=Uri(path="/hello")))
"PutFoo" === RRunner(c.toService()).checkOk(Request(method = Method.PUT, uri=Uri(path="/hello")))
"GetFoo" === RRunner(c.toRoutes()).checkOk(Request(uri=Uri(path="/hello")))
"PutFoo" === RRunner(c.toRoutes()).checkOk(Request(method = Method.PUT, uri=Uri(path="/hello")))
}

"Make routes from a collection of RhoRoutes" in {
Expand All @@ -39,7 +39,7 @@ class CompileRoutesSpec extends Specification {
(GET / "hello" |>> "GetFoo") ::
(PUT / "hello" |>> "PutFoo") :: Nil

val srvc = CompileRoutes.foldRoutes[IO](routes, identity)
val srvc = CompileRoutes.foldRoutes[IO](routes)
"GetFoo" === RRunner(srvc).checkOk(Request(uri=Uri(path="/hello")))
"PutFoo" === RRunner(srvc).checkOk(Request(method = Method.PUT, uri=Uri(path="/hello")))
}
Expand All @@ -48,7 +48,7 @@ class CompileRoutesSpec extends Specification {
val c1 = ServiceBuilder[IO](); getFoo(c1)
val c2 = ServiceBuilder[IO](); putFoo(c2)

val srvc = c1.append(c2.routes()).toService()
val srvc = c1.append(c2.routes()).toRoutes()
"GetFoo" === RRunner(srvc).checkOk(Request(uri=Uri(path="/hello")))
"PutFoo" === RRunner(srvc).checkOk(Request(method = Method.PUT, uri=Uri(path="/hello")))
}
Expand Down
13 changes: 7 additions & 6 deletions core/src/test/scala/org/http4s/rho/RequestRunner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,25 @@ import org.http4s.HttpRoutes
/** Helper for collecting a the body from a `RhoService` */
trait RequestRunner {

def service: HttpRoutes[IO]
def httpRoutes: HttpRoutes[IO]

def checkOk(r: Request[IO]): String = checkStatus(r)(_ == Status.Ok)
def checkOk(req: Request[IO]): String = checkStatus(req)(_ == Status.Ok)

def checkError(r: Request[IO]): String = checkStatus(r)(_ != Status.Ok)
def checkError(req: Request[IO]): String = checkStatus(req)(_ != Status.Ok)

def checkStatus(r: Request[IO])(isSuccess: Status => Boolean) = {
val resp = service(r).value.unsafeRunSync().getOrElse(Response.notFound)
def checkStatus(req: Request[IO])(isSuccess: Status => Boolean): String = {
val resp = httpRoutes(req).value.unsafeRunSync().getOrElse(Response.notFound)
if (isSuccess(resp.status)) getBody(resp.body)
else sys.error(s"Invalid response code: ${resp.status}")
}

val getBody = RequestRunner.getBody _
}

object RequestRunner {
def getBody(b: EntityBody[IO]): String = {
new String(b.compile.toVector.unsafeRunSync.foldLeft(Array[Byte]())(_ :+ _))
}
}

case class RRunner(service: HttpRoutes[IO]) extends RequestRunner
case class RRunner(httpRoutes: HttpRoutes[IO]) extends RequestRunner
8 changes: 4 additions & 4 deletions core/src/test/scala/org/http4s/rho/RhoServiceSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class RhoServiceSpec extends Specification with RequestRunner {
def Get(s: String, h: Header*): Request[IO] = construct(Method.GET, s, h:_*)
def Put(s: String, h: Header*): Request[IO] = construct(Method.PUT, s, h:_*)

val service = new RhoService[IO] {
val httpRoutes = new RhoService[IO] {
GET +? param("foo", "bar") |>> { foo: String => Ok(s"just root with parameter 'foo=$foo'") }

GET / "" +? param("foo", "bar") |>> { foo: String => Ok("this definition should be hidden by the previous definition") }
Expand Down Expand Up @@ -95,14 +95,14 @@ class RhoServiceSpec extends Specification with RequestRunner {

"Return a 405 when a path is defined but the method doesn't match" in {
val request = Request[IO](Method.POST, uri("/hello"))
val resp = service(request).value.unsafeRunSync().getOrElse(Response.notFound)
val resp = httpRoutes(request).value.unsafeRunSync().getOrElse(Response.notFound)

resp.status must_== Status.MethodNotAllowed
resp.headers.get("Allow".ci) must beSome(Header.Raw("Allow".ci, "GET"))
}

"Yield `MethodNotAllowed` when invalid method used" in {
service(Put("/one/two/three")).value.unsafeRunSync().getOrElse(Response.notFound).status must_== Status.MethodNotAllowed
httpRoutes(Put("/one/two/three")).value.unsafeRunSync().getOrElse(Response.notFound).status must_== Status.MethodNotAllowed
}

"Consider PathMatch(\"\") a NOOP" in {
Expand Down Expand Up @@ -148,7 +148,7 @@ class RhoServiceSpec extends Specification with RequestRunner {
}

"NotFound on empty route" in {
service(Get("/one/two")).value.unsafeRunSync().getOrElse(Response.notFound).status must_== Status.NotFound
httpRoutes(Get("/one/two")).value.unsafeRunSync().getOrElse(Response.notFound).status must_== Status.NotFound
}

"Fail a route with a missing query" in {
Expand Down

0 comments on commit acc4db3

Please sign in to comment.