Skip to content

Instantly share code, notes, and snippets.

@rossabaker
Created October 19, 2022 03:44
Show Gist options
  • Save rossabaker/c9c748449dd4061d38322b2d3a2b76c2 to your computer and use it in GitHub Desktop.
Save rossabaker/c9c748449dd4061d38322b2d3a2b76c2 to your computer and use it in GitHub Desktop.
import cats.Monad
import cats.StackSafeMonad
import cats.data.Kleisli
import cats.data.OptionT
import cats.effect.MonadCancel
import cats.effect.Resource
final class Routes[F[_], A, B] private (val run: A => Resource[F, Option[B]]) {
def map[C](f: B => C): Routes[F, A, C] =
Routes(run(_).map(_.map(f)))
def flatMap[C](f: B => Routes[F, A, C]): Routes[F, A, C] =
Routes(a => run(a).flatMap {
case Some(b) => f(b).run(a)
case None => Resource.pure(None)
})
def local[C](f: C => A): Routes[F, C, B] =
Routes((c: C) => run(f(c)))
def toKleisli(implicit F: MonadCancel[F, _]): Kleisli[Resource[OptionT[F, *], *], A, B] =
Kleisli(a => run(a).mapK(OptionT.liftK[F]).evalMap(OptionT.fromOption[F](_)))
}
object Routes {
def apply[F[_], A, B](run: A => Resource[F, Option[B]]): Routes[F, A, B] =
new Routes(run)
def pure[F[_], A, B](b: B) =
Routes((_: A) => Resource.pure[F, Option[B]](Some(b)))
def of[F[_], A, B](pf: PartialFunction[A, Resource[F, B]]): Routes[F, A, B] =
Routes(req => pf.lift(req) match {
case Some(resource) => resource.map(Some(_))
case None => Resource.pure(None)
})
def http[F[_]](pf: PartialFunction[Request[F], Resource[F, Response[F]]]): Routes[F, Request[F], Response[F]] =
of(pf)
implicit def monadInstance[F[_], A]: Monad[Routes[F, A, *]] =
new Monad[Routes[F, A, *]] with StackSafeMonad[Routes[F, A, *]] {
def pure[A](x: A) =
Routes.pure(x)
def flatMap[B, C](routes: Routes[F, A, B])(f: B => Routes[F, A, C]) =
routes.flatMap(f)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment