Skip to content

Instantly share code, notes, and snippets.

@pjambet
Last active January 7, 2020 21:02
Show Gist options
  • Save pjambet/cea3d2cb71d0b914d8b0d8cdf4d04003 to your computer and use it in GitHub Desktop.
Save pjambet/cea3d2cb71d0b914d8b0d8cdf4d04003 to your computer and use it in GitHub Desktop.
final case class OrderRequest(cardNumber: String)
// ...
val route =
path("order") {
post {
entity(as[OrderRequest]) { orderRequest =>
onComplete(PurchaseService.createPurchase(orderRequest.cardNumber)) {
case Success(Right(result)) =>
complete(StatusCodes.Created, result)
case Success(Left(error)) =>
val jsonError = "{\"error\": \"" + error.reason + "\"}"
complete(StatusCodes.PaymentRequired,
HttpEntity(ContentTypes.`application/json`, jsonError))
case Failure(exception) =>
// This is where exceptions would ideally be sent to a service like Bugsnag or Sentry
system.log.error(exception, "Unexpected error")
complete(StatusCodes.InternalServerError,
HttpEntity(ContentTypes.`application/json`,
"{\"error\": \"Something went wrong.\"}"))
}
}
}
}
object PurchaseService {
final case class Order(orderId: String)
final case class PurchaseError(reason: String)
def createPurchase(cardNumber: String)(
implicit ec: ExecutionContext): Future[Either[PurchaseError, Order]] = {
PaymentClient.chargeCard(cardNumber).map {
case Right(_) => Right(Order(orderId = UUID.randomUUID().toString))
case Left(error) => Left(PurchaseError(error.declineCode))
}
}
}
object PaymentClient {
final case class Charge(chargeId: UUID)
final case class ChargeFailure(declineCode: String)
final class PaymentException(message: String) extends Exception(message)
def chargeCard(cardNumber: String)(
implicit ec: ExecutionContext): Future[Either[ChargeFailure, Charge]] = {
// Fake an API call
Future {
if (cardNumber == "valid") {
Right(Charge(UUID.randomUUID()))
} else if (cardNumber.startsWith("card_error")) {
val declineCode = cardNumber.split("_").toList.drop(2).mkString("_")
Left(ChargeFailure(declineCode))
} else if (cardNumber == "rate_limit_error") {
throw new PaymentException("rate_limit_error")
} else if (cardNumber == "invalid_request_error") {
throw new PaymentException("invalid_request_error")
} else if (cardNumber == "authentication_error") {
throw new PaymentException("authentication_error")
} else if (cardNumber == "api_connection_error") {
throw new PaymentException("api_connection_error")
} else {
throw new PaymentException("unknown_error")
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment