in handlers/digital-voucher-api/src/main/scala/com/gu/digital_voucher_api/DigitalVoucherApiRoutes.scala [42:181]
def apply[F[_]: Effect](digitalVoucherService: DigitalVoucherService[F]): HttpRoutes[F] = {
type RouteResult[A] = EitherT[F, F[Response[F]], A]
object http4sDsl extends Http4sDsl[F]
import http4sDsl._
def parseRequest[A: Decoder](request: Request[F]): EitherT[F, F[Response[F]], A] = {
implicit val showDecodeFailure: Show[DecodeFailure] = Show.show[DecodeFailure] {
case InvalidMessageBodyFailure(details, cause) => s"InvalidMessageBodyFailure($details, $cause)"
case MalformedMessageBodyFailure(details, cause) => s"MalformedMessageBodyFailure($details, $cause)"
case error => error.toString
}
request
.attemptAs[A]
.leftMap { decodingFailure: DecodeFailure =>
BadRequest(DigitalVoucherApiRoutesError(s"Failed to decoded request body: ${decodingFailure.show}"))
}
}
def handleCreateRequest(request: Request[F], subscriptionId: SfSubscriptionId): F[Response[F]] = {
(for {
requestBody <- parseRequest[CreateVoucherRequestBody](request)
voucher <- digitalVoucherService
.createVoucher(subscriptionId, RatePlanName(requestBody.ratePlanName))
.leftMap {
case InvalidArgumentException(msg) =>
// see https://tools.ietf.org/html/rfc4918#section-11.2
UnprocessableEntity(DigitalVoucherApiRoutesError(s"Bad request argument: $msg"))
case ImovoOperationFailedException(msg) =>
BadGateway(DigitalVoucherApiRoutesError(s"Imovo failure to create voucher: $msg"))
case error =>
InternalServerError(DigitalVoucherApiRoutesError(s"Failed create voucher: $error"))
}
} yield Created(voucher)).merge.flatten
}
def handleReplaceRequest(request: Request[F]): F[Response[F]] = {
(for {
requestBody <- parseRequest[SubscriptionActionRequestBody](request)
subscriptionId <- requestBody.subscriptionId
.toRight(UnprocessableEntity(DigitalVoucherApiRoutesError(s"subscriptionId is required")))
.toEitherT[F]
replaceCard <- requestBody.replaceCard
.toRight(
UnprocessableEntity(
DigitalVoucherApiRoutesError(s"replaceCard flag is required when asking for a replacement"),
),
)
.toEitherT[F]
replaceLetter <- requestBody.replaceLetter
.toRight(
UnprocessableEntity(
DigitalVoucherApiRoutesError(s"replaceLetter flag is required when asking for a replacement"),
),
)
.toEitherT[F]
typeOfReplacement <- ImovoSubscriptionType
.fromBooleans(replaceCard, replaceLetter)
.toRight(
UnprocessableEntity(
DigitalVoucherApiRoutesError("Both replacement flags are set to false - nothing to replace"),
),
)
.toEitherT[F]
_ = typeOfReplacement
replacementVoucher <- digitalVoucherService
.replaceVoucher(SfSubscriptionId(subscriptionId), typeOfReplacement)
.leftMap(error => InternalServerError(DigitalVoucherApiRoutesError(s"Failed replace voucher: $error")))
} yield Ok(replacementVoucher)).merge.flatten
}
def handleGetRequest(subscriptionId: String): F[Response[F]] = {
digitalVoucherService
.getVoucher(subscriptionId)
.bimap(
error => InternalServerError(DigitalVoucherApiRoutesError(s"Failed get voucher: $error")),
voucher => Ok(voucher),
)
.merge
.flatten
}
def handleCancelRequest(request: Request[F]): F[Response[F]] = {
(for {
requestBody <- parseRequest[CancelSubscriptionVoucherRequestBody](request)
result <- digitalVoucherService
.cancelVouchers(SfSubscriptionId(requestBody.subscriptionId), requestBody.cancellationDate)
.leftMap(error => InternalServerError(DigitalVoucherApiRoutesError(s"Failed get voucher: $error")))
} yield Ok(result)).merge.flatten
}
def handleSuspendRequest(request: Request[F]): F[Response[F]] =
(for {
requestBody <- parseRequest[SuspendSubscriptionVoucherRequestBody](request)
subscriptionId <- requestBody.subscriptionId
.toRight(UnprocessableEntity(DigitalVoucherApiRoutesError(s"subscriptionId is required")))
.toEitherT[F]
startDate <- requestBody.startDate
.toRight(UnprocessableEntity(DigitalVoucherApiRoutesError(s"startDate is required")))
.toEitherT[F]
endDate <- requestBody.endDateExclusive
.toRight(UnprocessableEntity(DigitalVoucherApiRoutesError(s"endDateExclusive is required")))
.toEitherT[F]
result <- digitalVoucherService
.suspendVoucher(
SfSubscriptionId(subscriptionId),
startDate,
endDate,
)
.leftMap {
case ImovoOperationFailedException(msg) =>
BadGateway(DigitalVoucherApiRoutesError(s"Imovo failure to suspend voucher: $msg"))
case error =>
InternalServerError(DigitalVoucherApiRoutesError(s"Failed to suspend voucher: $error"))
}
} yield Ok(result)).merge.flatten
def handleRedemptionHistoryRequest(redemptionHistoryRequestBody: RedemptionHistoryRequestBody) = {
(for {
result <- digitalVoucherService
.getRedemptionHistory(redemptionHistoryRequestBody.subscriptionId)
.leftMap(error => InternalServerError(DigitalVoucherApiRoutesError(s"Failed get voucher: $error")))
} yield Ok(result)).merge.flatten
}
HttpRoutes.of[F] {
case _ @GET -> Root / "digital-voucher" / "redemption-history" / subscriptionId =>
handleRedemptionHistoryRequest(RedemptionHistoryRequestBody(subscriptionId))
case GET -> Root / "digital-voucher" / subscriptionId =>
handleGetRequest(subscriptionId)
case request @ POST -> Root / "digital-voucher" / "replace" =>
handleReplaceRequest(request)
case request @ POST -> Root / "digital-voucher" / "cancel" =>
handleCancelRequest(request)
case request @ PUT -> Root / "digital-voucher" / "suspend" =>
handleSuspendRequest(request)
case request @ PUT -> Root / "digital-voucher" / subscriptionId =>
handleCreateRequest(request, SfSubscriptionId(subscriptionId))
}
}