Skip to content

Instantly share code, notes, and snippets.

@mtranter
Created January 11, 2019 23:19
Show Gist options
  • Save mtranter/361edd3e4fa5aeb290337840f0e7a6ad to your computer and use it in GitHub Desktop.
Save mtranter/361edd3e4fa5aeb290337840f0e7a6ad to your computer and use it in GitHub Desktop.
Pure FP Scala Example
package com.trizzle
import cats.effect.IO
import cats.implicits._
import cats.{Applicative, Monad, MonadError}
import org.http4s.{Response, Status}
// Error ADT
sealed trait InvalidTopupReason
case object InvalidAmount extends InvalidTopupReason
case object InsufficientFunds extends InvalidTopupReason
case object BalanceExeedsMaxinum extends InvalidTopupReason
sealed trait TopupCardError extends Exception
case class InvalidRequestError(reason: InvalidTopupReason) extends TopupCardError
case object CardProviderConnectionError extends TopupCardError
case object PaymentProviderConnectionError extends TopupCardError
// Web Request
case class TopupRequest(id: String, amount: Double)
// Dependencies
trait RequestValidator[F[_]] {
def validateRequest(topupRequest: TopupRequest): F[Unit]
}
trait PaymentProviderClient[F[_]] {
def loadFundsToBank(amount: Double): F[Unit]
}
trait CardProviderClient[F[_]] {
def loadFundsOntoCard(id: String, amount: Double): F[Unit]
}
// Business Service
class TopupCardBusinessLogic[F[_]](implicit M: Monad[F], reqValidator: RequestValidator[F], ppClient: PaymentProviderClient[F], cpClient: CardProviderClient[F]) {
def doFundsLoad(req: TopupRequest): F[Unit] = for {
_ <- reqValidator.validateRequest(req)
_ <- ppClient.loadFundsToBank(req.amount)
_ <- cpClient.loadFundsOntoCard(req.id, req.amount)
} yield M.pure(())
}
// Some Web Layer
class WebLayer[F[_]: MonadError[?, Throwable]](implicit business: TopupCardBusinessLogic[F]) {
def post(request: TopupRequest) =
business
.doFundsLoad(request).map(_ => Response(Status.Ok))
.recover {
case InvalidRequestError(reason) => Response(Status.BadRequest, reason.toString)
case _ => Response(Status.InternalServerError)
}
}
// Main Method
object App {
val webServer = new WebLayer[IO]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment