I'm struggling a bit with how to translate an imperative style to a functional style.
In a imperative web request I'm used to saying something like the following psudo code:
public Response controllerAction(Request request) {
val (req, parserErrors) = parser.parseRequest(request);
if (parserErrors.any()) {
return FourHundredError(parserErrors);
}
val businessErrors = model.validate(req);
if (businessErrors.any()){
return FourOhFour(businessErrors);
}
val (response, errorsWithOurStuff) = model.doBusinessLogicStuff(req);
if (errorsWithOurStuff.any()) {
return FiveHundredError(errorsWithOurStuff);
}
return OK(response)
}
I'm trying to translate this into a functional style using http4s.
def businessRoutes[F[_]: Sync](BL: BusinessLogic[F]): HttpRoutes[F] = {
val dsl = new Http4sDsl[F]{}
import dsl._
HttpRoutes.of[F] {
case req @ POST -> Root / "sms" =>
for {
request <- req.as[BL.BuisnessRequest]
requestErrors <- BL.validateRequest(request)
response <- if (requestErrors.isEmpty) {
BL.processRequest(request) match {
case Failure(e) => InternalServerError(e)
case Success(response) => Ok(response)
}
} else {
BadRequest(requestErrors)
}
} yield response
}
}
The above code just looks... bad to me and I don't know how to make it better. My goal for this is to keep all the http style abstractions contained here, because I don't want to leak http4s or circe down into a business layer. I feel like I've got a for then an if, then a match and the responses are all jumbled together out of order. I'm writing hard to understand code here and I'm hoping some scala guru could show me how to clean this up and make this readable.