Created
May 31, 2018 20:48
-
-
Save hamnis/9299af62d1a388d36eabbf190b517460 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package no.scalabin.http4s.directives | |
package routes | |
import cats.Monad | |
import linx._ | |
import Route.{MethodPartial, ResponseDirective} | |
import org.http4s.{Method, Response, Status} | |
import scala.language.higherKinds | |
final class Route[F[+_]] private(val path: Linx[_, _])(pf: PartialFunction[String, ResponseDirective[F]]) extends PartialFunction[String, ResponseDirective[F]] { | |
override def isDefinedAt(x: String): Boolean = pf.isDefinedAt(x) | |
override def apply(v1: String): ResponseDirective[F] = pf.apply(v1) | |
} | |
final case class Methods[F[+_]](map: Map[Method, ResponseDirective[F]]) extends MethodPartial[F] { | |
override def isDefinedAt(x: Method): Boolean = map.isDefinedAt(x) | |
override def apply(v1: Method): ResponseDirective[F] = map(v1) | |
} | |
object Methods { | |
def apply[F[+_]](parts: (Method, ResponseDirective[F])*): Methods[F] = | |
Methods(parts.toMap) | |
} | |
object Route { | |
type ResponseDirective[F[+_]] = Directive[F, Response[F], Response[F]] | |
type MethodPartial[F[+_]] = PartialFunction[Method, ResponseDirective[F]] | |
def static[F[+_]: Monad](path: StaticLinx)(pf: MethodPartial[F]): Route[F] = { | |
new Route[F](path)({ | |
case path() => { | |
for { | |
req <- Directive.request | |
res <- if (pf.isDefinedAt(req.method)) pf(req.method) else Directive.error(Response[F](Status.MethodNotAllowed)) | |
} yield { | |
res | |
} | |
} | |
}) | |
} | |
def variable[F[+_]: Monad, A](path: Linx[A, Option[A]])(f: A => MethodPartial[F]): Route[F] = { | |
new Route[F](path)({ | |
case path(args) => { | |
val pf = f(args) | |
for { | |
req <- Directive.request | |
res <- if (pf.isDefinedAt(req.method)) pf(req.method) else Directive.error(Response[F](Status.MethodNotAllowed)) | |
} yield { | |
res | |
} | |
} | |
}) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package no.scalabin.http4s.directives | |
package routes | |
import cats.Monad | |
import cats.effect.{Effect, IO} | |
import fs2.{Stream, StreamApp} | |
import linx.StaticLinx | |
import Route.ResponseDirective | |
import org.http4s.server.blaze.BlazeBuilder | |
import org.http4s.{HttpService, Method} | |
import scala.concurrent.ExecutionContext | |
import scala.language.higherKinds | |
case class HealthCheck[F[+ _] : Monad](path: StaticLinx)(val rf: ResponseDirective[F]) { | |
val route: Route[F] = Route.static(path) { case Method.GET => rf } | |
} | |
case class Serve[F[+ _] : Effect](healthCheck: HealthCheck[F], port: Int) { | |
def stream(routes: Route[F]*)(implicit ec: ExecutionContext): Stream[F, StreamApp.ExitCode] = { | |
val completeRoutes = healthCheck.route :: routes.toList | |
val PathMapping = Plan[F]().PathMapping | |
val routesPF = completeRoutes.reduce[PartialFunction[String, ResponseDirective[F]]]((a, b) => a orElse b) | |
val service = HttpService[F](PathMapping(routesPF)) | |
println("%-6s".format("**** Serving the following routes *****")) | |
completeRoutes.foreach(r => println("%s".format(r.path))) | |
BlazeBuilder[F] | |
.bindHttp(port, "localhost") | |
.enableHttp2(true) | |
.withWebSockets(true) | |
.mountService(service, "/") | |
.serve | |
} | |
} | |
object TestApp extends StreamApp[IO] { | |
import org.http4s.dsl.io._ | |
import scala.concurrent.ExecutionContext.Implicits.global | |
override def stream(args: List[String], requestShutdown: IO[Unit]): Stream[IO, StreamApp.ExitCode] = | |
Serve(HealthCheck(linx.Root / "health")(Directive.successF(Ok("Hello Y'all"))), 1337).stream( | |
Route.variable(linx.Root / "so" / "hello" / 'name)(name => { | |
case Method.GET => Directive.successF(Ok(s"Hello $name")) | |
} | |
), | |
Route.variable(linx.Root / 'greeting / 'name) { | |
case (greeting, name) => | |
Methods( | |
Method.GET -> Directive.successF(Ok(s"$greeting, $name")), | |
Method.POST -> Directive.successF(Ok(s"$greeting, $name from POST")) | |
) | |
} | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment